summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2010-06-28 22:10:42 +0000
committerNicholas Marriott <nicm@openbsd.org>2010-06-28 22:10:42 +0000
commit76bbdeb586ad93cfb16bd12db865b4c672a9168e (patch)
tree52ecf7ef2f819396844962ffaf1edbcb4e3bf6b1
parent07a71fd432df5873515da82d2d620ec0d986b558 (diff)
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).
-rw-r--r--client.c11
-rw-r--r--cmd-load-buffer.c31
-rw-r--r--cmd-save-buffer.c33
-rw-r--r--server-client.c66
-rw-r--r--tmux.c12
-rw-r--r--tmux.h15
6 files changed, 117 insertions, 51 deletions
diff --git a/client.c b/client.c
index 35cf2801..e86a64ad 100644
--- a/client.c
+++ b/client.c
@@ -96,8 +96,7 @@ server_started:
if (cmdflags & CMD_SENDENVIRON)
client_send_environ();
- if (isatty(STDIN_FILENO))
- client_send_identify(flags);
+ client_send_identify(flags);
return (&client_ibuf);
@@ -131,6 +130,14 @@ client_send_identify(int flags)
fatal("dup failed");
imsg_compose(&client_ibuf,
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
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 1fe95818..0f118490 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -16,10 +16,13 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <sys/types.h>
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.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 session *s;
- FILE *f;
+ FILE *f, *close_f;
char *pdata, *new_pdata;
size_t psize;
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)
return (-1);
- if ((f = fopen(data->arg, "rb")) == NULL) {
- ctx->error(ctx, "%s: %s", data->arg, strerror(errno));
- return (-1);
+ if (strcmp(data->arg, "-") == 0 ) {
+ if (ctx->cmdclient == NULL) {
+ 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;
@@ -77,7 +94,8 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
if (pdata != NULL)
pdata[psize] = '\0';
- fclose(f);
+ if (close_f != NULL)
+ fclose(close_f);
limit = options_get_number(&s->options, "buffer-limit");
if (data->buffer == -1) {
@@ -94,6 +112,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
error:
if (pdata != NULL)
xfree(pdata);
- fclose(f);
+ if (close_f != NULL)
+ fclose(close_f);
return (-1);
}
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 22bc44f8..57c3f5f0 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -48,7 +48,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
struct session *s;
struct paste_buffer *pb;
mode_t mask;
- FILE *f;
+ FILE *f, *close_f;
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
@@ -65,15 +65,25 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
- 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);
+ if (strcmp(data->arg, "-") == 0) {
+ if (ctx->cmdclient == NULL) {
+ ctx->error(ctx, "%s: can't write to stdout", data->arg);
+ return (-1);
+ }
+ f = ctx->cmdclient->stdout_file;
+ close_f = NULL;
+ } else {
+ 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) {
@@ -82,7 +92,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
}
- fclose(f);
+ if (close_f != NULL)
+ fclose(close_f);
return (0);
}
diff --git a/server-client.c b/server-client.c
index 301c986a..c7929fc1 100644
--- a/server-client.c
+++ b/server-client.c
@@ -69,6 +69,10 @@ server_client_create(int fd)
ARRAY_INIT(&c->prompt_hdata);
+ c->stdin_file = NULL;
+ c->stdout_file = NULL;
+ c->stderr_file = NULL;
+
c->tty.fd = -1;
c->title = NULL;
@@ -118,6 +122,13 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL)
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);
job_tree_free(&c->status_jobs);
@@ -555,8 +566,31 @@ server_client_msg_dispatch(struct client *c)
fatalx("MSG_IDENTIFY missing fd");
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);
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:
if (datalen != 0)
fatalx("bad MSG_RESIZE size");
@@ -622,45 +656,45 @@ server_client_msg_dispatch(struct client *c)
void printflike2
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);
- xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
+ vfprintf(ctx->cmdclient->stderr_file, fmt, 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. */
void printflike2
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);
- xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
+ vfprintf(ctx->cmdclient->stdout_file, fmt, 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. */
void printflike2
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"))
return;
va_start(ap, fmt);
- xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
+ vfprintf(ctx->cmdclient->stdout_file, fmt, 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. */
@@ -717,13 +751,19 @@ void
server_client_msg_identify(
struct client *c, struct msg_identify_data *data, int fd)
{
+ int tty_fd;
+
c->cwd = NULL;
data->cwd[(sizeof data->cwd) - 1] = '\0';
if (*data->cwd != '\0')
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';
- tty_init(&c->tty, fd, data->term);
+ tty_init(&c->tty, tty_fd, data->term);
if (data->flags & IDENTIFY_UTF8)
c->tty.flags |= TTY_UTF8;
if (data->flags & IDENTIFY_256COLOURS)
diff --git a/tmux.c b/tmux.c
index dc5631be..1c9d1cb5 100644
--- a/tmux.c
+++ b/tmux.c
@@ -596,7 +596,6 @@ main_dispatch(const char *shellcmd)
{
struct imsg imsg;
ssize_t n, datalen;
- struct msg_print_data printdata;
struct msg_shell_data shelldata;
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
@@ -616,17 +615,6 @@ main_dispatch(const char *shellcmd)
fatalx("bad MSG_EXIT size");
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:
if (datalen != 0)
fatalx("bad MSG_READY size");
diff --git a/tmux.h b/tmux.h
index 88a8e814..9b46a4f4 100644
--- a/tmux.h
+++ b/tmux.h
@@ -19,7 +19,7 @@
#ifndef TMUX_H
#define TMUX_H
-#define PROTOCOL_VERSION 5
+#define PROTOCOL_VERSION 6
#include <sys/param.h>
#include <sys/time.h>
@@ -68,7 +68,6 @@ extern char **environ;
*/
#define COMMAND_LENGTH 2048 /* packed argv size */
#define TERMINAL_LENGTH 128 /* length of TERM environment variable */
-#define PRINT_LENGTH 512 /* printed error/message size */
#define ENVIRON_LENGTH 1024 /* environment variable length */
/*
@@ -373,7 +372,9 @@ enum msgtype {
MSG_ENVIRON,
MSG_UNLOCK,
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!
*/
-struct msg_print_data {
- char msg[PRINT_LENGTH];
-};
-
struct msg_command_data {
pid_t pid; /* pid from $TMUX or -1 */
u_int idx; /* index from $TMUX */
@@ -1080,6 +1077,10 @@ struct client {
char *cwd;
struct tty tty;
+ FILE *stdin_file;
+ FILE *stdout_file;
+ FILE *stderr_file;
+
struct event repeat_timer;
struct timeval status_timer;