mirror of
https://github.com/tmux/tmux.git
synced 2025-04-10 02:58:50 +00:00
Send all three of stdin, stdout, stderr from the client to the server, so that
commands can directly make use of them. This means that load-buffer and save-buffer can have "-" as the file to read from stdin or write to stdout. This is a protocol version bump so the tmux server will need to be restarted after upgrade (or an older client used).
This commit is contained in:
parent
07a71fd432
commit
76bbdeb586
11
client.c
11
client.c
@ -96,8 +96,7 @@ server_started:
|
|||||||
|
|
||||||
if (cmdflags & CMD_SENDENVIRON)
|
if (cmdflags & CMD_SENDENVIRON)
|
||||||
client_send_environ();
|
client_send_environ();
|
||||||
if (isatty(STDIN_FILENO))
|
client_send_identify(flags);
|
||||||
client_send_identify(flags);
|
|
||||||
|
|
||||||
return (&client_ibuf);
|
return (&client_ibuf);
|
||||||
|
|
||||||
@ -131,6 +130,14 @@ client_send_identify(int flags)
|
|||||||
fatal("dup failed");
|
fatal("dup failed");
|
||||||
imsg_compose(&client_ibuf,
|
imsg_compose(&client_ibuf,
|
||||||
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
|
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
|
||||||
|
|
||||||
|
if ((fd = dup(STDOUT_FILENO)) == -1)
|
||||||
|
fatal("dup failed");
|
||||||
|
imsg_compose(&client_ibuf, MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
|
||||||
|
|
||||||
|
if ((fd = dup(STDERR_FILENO)) == -1)
|
||||||
|
fatal("dup failed");
|
||||||
|
imsg_compose(&client_ibuf, MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -16,10 +16,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
@ -45,7 +48,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
{
|
{
|
||||||
struct cmd_buffer_data *data = self->data;
|
struct cmd_buffer_data *data = self->data;
|
||||||
struct session *s;
|
struct session *s;
|
||||||
FILE *f;
|
FILE *f, *close_f;
|
||||||
char *pdata, *new_pdata;
|
char *pdata, *new_pdata;
|
||||||
size_t psize;
|
size_t psize;
|
||||||
u_int limit;
|
u_int limit;
|
||||||
@ -54,9 +57,23 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if ((f = fopen(data->arg, "rb")) == NULL) {
|
if (strcmp(data->arg, "-") == 0 ) {
|
||||||
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
|
if (ctx->cmdclient == NULL) {
|
||||||
return (-1);
|
ctx->error(ctx, "%s: can't read from stdin", data->arg);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
f = ctx->cmdclient->stdin_file;
|
||||||
|
if (isatty(fileno(ctx->cmdclient->stdin_file))) {
|
||||||
|
ctx->error(ctx, "%s: stdin is a tty", data->arg);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
close_f = NULL;
|
||||||
|
} else {
|
||||||
|
if ((f = fopen(data->arg, "rb")) == NULL) {
|
||||||
|
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
close_f = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdata = NULL;
|
pdata = NULL;
|
||||||
@ -77,7 +94,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
if (pdata != NULL)
|
if (pdata != NULL)
|
||||||
pdata[psize] = '\0';
|
pdata[psize] = '\0';
|
||||||
|
|
||||||
fclose(f);
|
if (close_f != NULL)
|
||||||
|
fclose(close_f);
|
||||||
|
|
||||||
limit = options_get_number(&s->options, "buffer-limit");
|
limit = options_get_number(&s->options, "buffer-limit");
|
||||||
if (data->buffer == -1) {
|
if (data->buffer == -1) {
|
||||||
@ -94,6 +112,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
error:
|
error:
|
||||||
if (pdata != NULL)
|
if (pdata != NULL)
|
||||||
xfree(pdata);
|
xfree(pdata);
|
||||||
fclose(f);
|
if (close_f != NULL)
|
||||||
|
fclose(close_f);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
struct session *s;
|
struct session *s;
|
||||||
struct paste_buffer *pb;
|
struct paste_buffer *pb;
|
||||||
mode_t mask;
|
mode_t mask;
|
||||||
FILE *f;
|
FILE *f, *close_f;
|
||||||
|
|
||||||
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
if ((s = cmd_find_session(ctx, data->target)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -65,15 +65,25 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mask = umask(S_IRWXG | S_IRWXO);
|
if (strcmp(data->arg, "-") == 0) {
|
||||||
if (cmd_check_flag(data->chflags, 'a'))
|
if (ctx->cmdclient == NULL) {
|
||||||
f = fopen(data->arg, "ab");
|
ctx->error(ctx, "%s: can't write to stdout", data->arg);
|
||||||
else
|
return (-1);
|
||||||
f = fopen(data->arg, "wb");
|
}
|
||||||
umask(mask);
|
f = ctx->cmdclient->stdout_file;
|
||||||
if (f == NULL) {
|
close_f = NULL;
|
||||||
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
|
} else {
|
||||||
return (-1);
|
mask = umask(S_IRWXG | S_IRWXO);
|
||||||
|
if (cmd_check_flag(data->chflags, 'a'))
|
||||||
|
f = fopen(data->arg, "ab");
|
||||||
|
else
|
||||||
|
f = fopen(data->arg, "wb");
|
||||||
|
umask(mask);
|
||||||
|
if (f == NULL) {
|
||||||
|
ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
close_f = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
|
if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
|
||||||
@ -82,7 +92,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
if (close_f != NULL)
|
||||||
|
fclose(close_f);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,10 @@ server_client_create(int fd)
|
|||||||
|
|
||||||
ARRAY_INIT(&c->prompt_hdata);
|
ARRAY_INIT(&c->prompt_hdata);
|
||||||
|
|
||||||
|
c->stdin_file = NULL;
|
||||||
|
c->stdout_file = NULL;
|
||||||
|
c->stderr_file = NULL;
|
||||||
|
|
||||||
c->tty.fd = -1;
|
c->tty.fd = -1;
|
||||||
c->title = NULL;
|
c->title = NULL;
|
||||||
|
|
||||||
@ -118,6 +122,13 @@ server_client_lost(struct client *c)
|
|||||||
if (c->flags & CLIENT_TERMINAL)
|
if (c->flags & CLIENT_TERMINAL)
|
||||||
tty_free(&c->tty);
|
tty_free(&c->tty);
|
||||||
|
|
||||||
|
if (c->stdin_file != NULL)
|
||||||
|
fclose(c->stdin_file);
|
||||||
|
if (c->stdout_file != NULL)
|
||||||
|
fclose(c->stdout_file);
|
||||||
|
if (c->stderr_file != NULL)
|
||||||
|
fclose(c->stderr_file);
|
||||||
|
|
||||||
screen_free(&c->status);
|
screen_free(&c->status);
|
||||||
job_tree_free(&c->status_jobs);
|
job_tree_free(&c->status_jobs);
|
||||||
|
|
||||||
@ -555,8 +566,31 @@ server_client_msg_dispatch(struct client *c)
|
|||||||
fatalx("MSG_IDENTIFY missing fd");
|
fatalx("MSG_IDENTIFY missing fd");
|
||||||
memcpy(&identifydata, imsg.data, sizeof identifydata);
|
memcpy(&identifydata, imsg.data, sizeof identifydata);
|
||||||
|
|
||||||
|
c->stdin_file = fdopen(imsg.fd, "r");
|
||||||
|
if (c->stdin_file == NULL)
|
||||||
|
fatal("fdopen(stdin) failed");
|
||||||
server_client_msg_identify(c, &identifydata, imsg.fd);
|
server_client_msg_identify(c, &identifydata, imsg.fd);
|
||||||
break;
|
break;
|
||||||
|
case MSG_STDOUT:
|
||||||
|
if (datalen != 0)
|
||||||
|
fatalx("bad MSG_STDOUT size");
|
||||||
|
if (imsg.fd == -1)
|
||||||
|
fatalx("MSG_STDOUT missing fd");
|
||||||
|
|
||||||
|
c->stdout_file = fdopen(imsg.fd, "w");
|
||||||
|
if (c->stdout_file == NULL)
|
||||||
|
fatal("fdopen(stdout) failed");
|
||||||
|
break;
|
||||||
|
case MSG_STDERR:
|
||||||
|
if (datalen != 0)
|
||||||
|
fatalx("bad MSG_STDERR size");
|
||||||
|
if (imsg.fd == -1)
|
||||||
|
fatalx("MSG_STDERR missing fd");
|
||||||
|
|
||||||
|
c->stderr_file = fdopen(imsg.fd, "w");
|
||||||
|
if (c->stderr_file == NULL)
|
||||||
|
fatal("fdopen(stderr) failed");
|
||||||
|
break;
|
||||||
case MSG_RESIZE:
|
case MSG_RESIZE:
|
||||||
if (datalen != 0)
|
if (datalen != 0)
|
||||||
fatalx("bad MSG_RESIZE size");
|
fatalx("bad MSG_RESIZE size");
|
||||||
@ -622,45 +656,45 @@ server_client_msg_dispatch(struct client *c)
|
|||||||
void printflike2
|
void printflike2
|
||||||
server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
|
server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct msg_print_data data;
|
va_list ap;
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
|
vfprintf(ctx->cmdclient->stderr_file, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
|
fputc('\n', ctx->cmdclient->stderr_file);
|
||||||
|
fflush(ctx->cmdclient->stderr_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback to send print message to client. */
|
/* Callback to send print message to client. */
|
||||||
void printflike2
|
void printflike2
|
||||||
server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
|
server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct msg_print_data data;
|
va_list ap;
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
|
vfprintf(ctx->cmdclient->stdout_file, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
|
fputc('\n', ctx->cmdclient->stdout_file);
|
||||||
|
fflush(ctx->cmdclient->stdout_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback to send print message to client, if not quiet. */
|
/* Callback to send print message to client, if not quiet. */
|
||||||
void printflike2
|
void printflike2
|
||||||
server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
|
server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
struct msg_print_data data;
|
va_list ap;
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
if (options_get_number(&global_options, "quiet"))
|
if (options_get_number(&global_options, "quiet"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
|
vfprintf(ctx->cmdclient->stdout_file, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
|
fputc('\n', ctx->cmdclient->stderr_file);
|
||||||
|
fflush(ctx->cmdclient->stdout_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle command message. */
|
/* Handle command message. */
|
||||||
@ -717,13 +751,19 @@ void
|
|||||||
server_client_msg_identify(
|
server_client_msg_identify(
|
||||||
struct client *c, struct msg_identify_data *data, int fd)
|
struct client *c, struct msg_identify_data *data, int fd)
|
||||||
{
|
{
|
||||||
|
int tty_fd;
|
||||||
|
|
||||||
c->cwd = NULL;
|
c->cwd = NULL;
|
||||||
data->cwd[(sizeof data->cwd) - 1] = '\0';
|
data->cwd[(sizeof data->cwd) - 1] = '\0';
|
||||||
if (*data->cwd != '\0')
|
if (*data->cwd != '\0')
|
||||||
c->cwd = xstrdup(data->cwd);
|
c->cwd = xstrdup(data->cwd);
|
||||||
|
|
||||||
|
if (!isatty(fd))
|
||||||
|
return;
|
||||||
|
if ((tty_fd = dup(fd)) == -1)
|
||||||
|
fatal("dup failed");
|
||||||
data->term[(sizeof data->term) - 1] = '\0';
|
data->term[(sizeof data->term) - 1] = '\0';
|
||||||
tty_init(&c->tty, fd, data->term);
|
tty_init(&c->tty, tty_fd, data->term);
|
||||||
if (data->flags & IDENTIFY_UTF8)
|
if (data->flags & IDENTIFY_UTF8)
|
||||||
c->tty.flags |= TTY_UTF8;
|
c->tty.flags |= TTY_UTF8;
|
||||||
if (data->flags & IDENTIFY_256COLOURS)
|
if (data->flags & IDENTIFY_256COLOURS)
|
||||||
|
12
tmux.c
12
tmux.c
@ -596,7 +596,6 @@ main_dispatch(const char *shellcmd)
|
|||||||
{
|
{
|
||||||
struct imsg imsg;
|
struct imsg imsg;
|
||||||
ssize_t n, datalen;
|
ssize_t n, datalen;
|
||||||
struct msg_print_data printdata;
|
|
||||||
struct msg_shell_data shelldata;
|
struct msg_shell_data shelldata;
|
||||||
|
|
||||||
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
|
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
|
||||||
@ -616,17 +615,6 @@ main_dispatch(const char *shellcmd)
|
|||||||
fatalx("bad MSG_EXIT size");
|
fatalx("bad MSG_EXIT size");
|
||||||
|
|
||||||
exit(main_exitval);
|
exit(main_exitval);
|
||||||
case MSG_ERROR:
|
|
||||||
case MSG_PRINT:
|
|
||||||
if (datalen != sizeof printdata)
|
|
||||||
fatalx("bad MSG_PRINT size");
|
|
||||||
memcpy(&printdata, imsg.data, sizeof printdata);
|
|
||||||
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
|
|
||||||
|
|
||||||
log_info("%s", printdata.msg);
|
|
||||||
if (imsg.hdr.type == MSG_ERROR)
|
|
||||||
main_exitval = 1;
|
|
||||||
break;
|
|
||||||
case MSG_READY:
|
case MSG_READY:
|
||||||
if (datalen != 0)
|
if (datalen != 0)
|
||||||
fatalx("bad MSG_READY size");
|
fatalx("bad MSG_READY size");
|
||||||
|
15
tmux.h
15
tmux.h
@ -19,7 +19,7 @@
|
|||||||
#ifndef TMUX_H
|
#ifndef TMUX_H
|
||||||
#define TMUX_H
|
#define TMUX_H
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 5
|
#define PROTOCOL_VERSION 6
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@ -68,7 +68,6 @@ extern char **environ;
|
|||||||
*/
|
*/
|
||||||
#define COMMAND_LENGTH 2048 /* packed argv size */
|
#define COMMAND_LENGTH 2048 /* packed argv size */
|
||||||
#define TERMINAL_LENGTH 128 /* length of TERM environment variable */
|
#define TERMINAL_LENGTH 128 /* length of TERM environment variable */
|
||||||
#define PRINT_LENGTH 512 /* printed error/message size */
|
|
||||||
#define ENVIRON_LENGTH 1024 /* environment variable length */
|
#define ENVIRON_LENGTH 1024 /* environment variable length */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -373,7 +372,9 @@ enum msgtype {
|
|||||||
MSG_ENVIRON,
|
MSG_ENVIRON,
|
||||||
MSG_UNLOCK,
|
MSG_UNLOCK,
|
||||||
MSG_LOCK,
|
MSG_LOCK,
|
||||||
MSG_SHELL
|
MSG_SHELL,
|
||||||
|
MSG_STDERR,
|
||||||
|
MSG_STDOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -381,10 +382,6 @@ enum msgtype {
|
|||||||
*
|
*
|
||||||
* Don't forget to bump PROTOCOL_VERSION if any of these change!
|
* Don't forget to bump PROTOCOL_VERSION if any of these change!
|
||||||
*/
|
*/
|
||||||
struct msg_print_data {
|
|
||||||
char msg[PRINT_LENGTH];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct msg_command_data {
|
struct msg_command_data {
|
||||||
pid_t pid; /* pid from $TMUX or -1 */
|
pid_t pid; /* pid from $TMUX or -1 */
|
||||||
u_int idx; /* index from $TMUX */
|
u_int idx; /* index from $TMUX */
|
||||||
@ -1080,6 +1077,10 @@ struct client {
|
|||||||
char *cwd;
|
char *cwd;
|
||||||
|
|
||||||
struct tty tty;
|
struct tty tty;
|
||||||
|
FILE *stdin_file;
|
||||||
|
FILE *stdout_file;
|
||||||
|
FILE *stderr_file;
|
||||||
|
|
||||||
struct event repeat_timer;
|
struct event repeat_timer;
|
||||||
|
|
||||||
struct timeval status_timer;
|
struct timeval status_timer;
|
||||||
|
Loading…
Reference in New Issue
Block a user