aboutsummaryrefslogtreecommitdiff
path: root/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'client.c')
-rw-r--r--client.c64
1 files changed, 49 insertions, 15 deletions
diff --git a/client.c b/client.c
index 10b77ad3..ed182dbb 100644
--- a/client.c
+++ b/client.c
@@ -35,6 +35,7 @@
struct imsgbuf client_ibuf;
struct event client_event;
+struct event client_stdin;
enum {
CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED,
@@ -56,6 +57,7 @@ void client_send_environ(void);
void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void);
void client_signal(int, short, void *);
+void client_stdin_callback(int, short, void *);
void client_callback(int, short, void *);
int client_dispatch_attached(void);
int client_dispatch_wait(void *);
@@ -229,6 +231,11 @@ client_main(int argc, char **argv, int flags)
imsg_init(&client_ibuf, fd);
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
+ /* Create stdin handler. */
+ setblocking(STDIN_FILENO, 0);
+ event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
+ client_stdin_callback, NULL);
+
/* Establish signal handlers. */
set_signals(client_signal);
@@ -257,6 +264,7 @@ client_main(int argc, char **argv, int flags)
/* Set the event and dispatch. */
client_update_event();
+ event_add (&client_stdin, NULL);
event_dispatch();
/* Print the exit message, if any, and exit. */
@@ -268,6 +276,7 @@ client_main(int argc, char **argv, int flags)
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
}
+ setblocking(STDIN_FILENO, 1);
return (client_exitval);
}
@@ -289,20 +298,11 @@ client_send_identify(int flags)
strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
*data.term = '\0';
- 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);
-
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
+ client_update_event();
}
/* Forward entire environment to server. */
@@ -324,6 +324,7 @@ void
client_write_server(enum msgtype type, void *buf, size_t len)
{
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
+ client_update_event();
}
/* Update client event based on whether it needs to read or read and write. */
@@ -423,6 +424,23 @@ lost_server:
event_loopexit(NULL);
}
+/* Callback for client stdin read events. */
+/* ARGSUSED */
+void
+client_stdin_callback(unused int fd, unused short events, unused void *data1)
+{
+ struct msg_stdin_data data;
+
+ data.size = read(STDIN_FILENO, data.data, sizeof data.data);
+ if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
+ return;
+
+ client_write_server(MSG_STDIN, &data, sizeof data);
+ if (data.size <= 0)
+ event_del(&client_stdin);
+ client_update_event();
+}
+
/* Dispatch imsgs when in wait state (before MSG_READY). */
int
client_dispatch_wait(void *data)
@@ -431,11 +449,10 @@ client_dispatch_wait(void *data)
ssize_t n, datalen;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata;
+ struct msg_stdout_data stdoutdata;
+ struct msg_stderr_data stderrdata;
const char *shellcmd = data;
- if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
- fatalx("imsg_read failed");
-
for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
@@ -443,6 +460,7 @@ client_dispatch_wait(void *data)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ log_debug("got %d from server", imsg.hdr.type);
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
@@ -459,14 +477,30 @@ client_dispatch_wait(void *data)
if (datalen != 0)
fatalx("bad MSG_READY size");
+ event_del(&client_stdin);
client_attached = 1;
break;
+ case MSG_STDOUT:
+ if (datalen != sizeof stdoutdata)
+ fatalx("bad MSG_STDOUT");
+ memcpy(&stdoutdata, imsg.data, sizeof stdoutdata);
+
+ fwrite(stdoutdata.data, stdoutdata.size, 1, stdout);
+ break;
+ case MSG_STDERR:
+ if (datalen != sizeof stderrdata)
+ fatalx("bad MSG_STDERR");
+ memcpy(&stderrdata, imsg.data, sizeof stderrdata);
+
+ fwrite(stderrdata.data, stderrdata.size, 1, stderr);
+ break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
- log_warnx("protocol version mismatch (client %u, "
- "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
+ fprintf(stderr, "protocol version mismatch "
+ "(client %u, server %u)\n", PROTOCOL_VERSION,
+ imsg.hdr.peerid);
client_exitval = 1;
imsg_free(&imsg);