1
0
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:
Nicholas Marriott 2010-06-28 22:10:42 +00:00
parent 07a71fd432
commit 76bbdeb586
6 changed files with 117 additions and 51 deletions

View File

@ -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

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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
View File

@ -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
View File

@ -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;