1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "tmux.h"
29 
30 /*
31  * IPC file handling. Both client and server use the same data structures
32  * (client_file and client_files) to store list of active files. Most functions
33  * are for use either in client or server but not both.
34  */
35 
36 static int	file_next_stream = 3;
37 
38 RB_GENERATE(client_files, client_file, entry, file_cmp);
39 
40 /* Get path for file, either as given or from working directory. */
41 static char *
file_get_path(struct client * c,const char * file)42 file_get_path(struct client *c, const char *file)
43 {
44 	char	*path;
45 
46 	if (*file == '/')
47 		path = xstrdup(file);
48 	else
49 		xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file);
50 	return (path);
51 }
52 
53 /* Tree comparison function. */
54 int
file_cmp(struct client_file * cf1,struct client_file * cf2)55 file_cmp(struct client_file *cf1, struct client_file *cf2)
56 {
57 	if (cf1->stream < cf2->stream)
58 		return (-1);
59 	if (cf1->stream > cf2->stream)
60 		return (1);
61 	return (0);
62 }
63 
64 /*
65  * Create a file object in the client process - the peer is the server to send
66  * messages to. Check callback is fired when the file is finished with so the
67  * process can decide if it needs to exit (if it is waiting for files to
68  * flush).
69  */
70 struct client_file *
file_create_with_peer(struct tmuxpeer * peer,struct client_files * files,int stream,client_file_cb cb,void * cbdata)71 file_create_with_peer(struct tmuxpeer *peer, struct client_files *files,
72     int stream, client_file_cb cb, void *cbdata)
73 {
74 	struct client_file	*cf;
75 
76 	cf = xcalloc(1, sizeof *cf);
77 	cf->c = NULL;
78 	cf->references = 1;
79 	cf->stream = stream;
80 
81 	cf->buffer = evbuffer_new();
82 	if (cf->buffer == NULL)
83 		fatalx("out of memory");
84 
85 	cf->cb = cb;
86 	cf->data = cbdata;
87 
88 	cf->peer = peer;
89 	cf->tree = files;
90 	RB_INSERT(client_files, files, cf);
91 
92 	return (cf);
93 }
94 
95 /* Create a file object in the server, communicating with the given client. */
96 struct client_file *
file_create_with_client(struct client * c,int stream,client_file_cb cb,void * cbdata)97 file_create_with_client(struct client *c, int stream, client_file_cb cb,
98     void *cbdata)
99 {
100 	struct client_file	*cf;
101 
102 	if (c != NULL && (c->flags & CLIENT_ATTACHED))
103 		c = NULL;
104 
105 	cf = xcalloc(1, sizeof *cf);
106 	cf->c = c;
107 	cf->references = 1;
108 	cf->stream = stream;
109 
110 	cf->buffer = evbuffer_new();
111 	if (cf->buffer == NULL)
112 		fatalx("out of memory");
113 
114 	cf->cb = cb;
115 	cf->data = cbdata;
116 
117 	if (cf->c != NULL) {
118 		cf->peer = cf->c->peer;
119 		cf->tree = &cf->c->files;
120 		RB_INSERT(client_files, &cf->c->files, cf);
121 		cf->c->references++;
122 	}
123 
124 	return (cf);
125 }
126 
127 /* Free a file. */
128 void
file_free(struct client_file * cf)129 file_free(struct client_file *cf)
130 {
131 	if (--cf->references != 0)
132 		return;
133 
134 	evbuffer_free(cf->buffer);
135 	free(cf->path);
136 
137 	if (cf->tree != NULL)
138 		RB_REMOVE(client_files, cf->tree, cf);
139 	if (cf->c != NULL)
140 		server_client_unref(cf->c);
141 
142 	free(cf);
143 }
144 
145 /* Event to fire the done callback. */
146 static void
file_fire_done_cb(__unused int fd,__unused short events,void * arg)147 file_fire_done_cb(__unused int fd, __unused short events, void *arg)
148 {
149 	struct client_file	*cf = arg;
150 	struct client		*c = cf->c;
151 
152 	if (cf->cb != NULL && (c == NULL || (~c->flags & CLIENT_DEAD)))
153 		cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
154 	file_free(cf);
155 }
156 
157 /* Add an event to fire the done callback (used by the server). */
158 void
file_fire_done(struct client_file * cf)159 file_fire_done(struct client_file *cf)
160 {
161 	event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL);
162 }
163 
164 /* Fire the read callback. */
165 void
file_fire_read(struct client_file * cf)166 file_fire_read(struct client_file *cf)
167 {
168 	if (cf->cb != NULL)
169 		cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data);
170 }
171 
172 /* Can this file be printed to? */
173 int
file_can_print(struct client * c)174 file_can_print(struct client *c)
175 {
176 	if (c == NULL)
177 		return (0);
178 	if (c->session != NULL && (~c->flags & CLIENT_CONTROL))
179 		return (0);
180 	return (1);
181 }
182 
183 /* Print a message to a file. */
184 void
file_print(struct client * c,const char * fmt,...)185 file_print(struct client *c, const char *fmt, ...)
186 {
187 	va_list	ap;
188 
189 	va_start(ap, fmt);
190 	file_vprint(c, fmt, ap);
191 	va_end(ap);
192 }
193 
194 /* Print a message to a file. */
195 void
file_vprint(struct client * c,const char * fmt,va_list ap)196 file_vprint(struct client *c, const char *fmt, va_list ap)
197 {
198 	struct client_file	 find, *cf;
199 	struct msg_write_open	 msg;
200 
201 	if (!file_can_print(c))
202 		return;
203 
204 	find.stream = 1;
205 	if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
206 		cf = file_create_with_client(c, 1, NULL, NULL);
207 		cf->path = xstrdup("-");
208 
209 		evbuffer_add_vprintf(cf->buffer, fmt, ap);
210 
211 		msg.stream = 1;
212 		msg.fd = STDOUT_FILENO;
213 		msg.flags = 0;
214 		proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
215 	} else {
216 		evbuffer_add_vprintf(cf->buffer, fmt, ap);
217 		file_push(cf);
218 	}
219 }
220 
221 /* Print a buffer to a file. */
222 void
file_print_buffer(struct client * c,void * data,size_t size)223 file_print_buffer(struct client *c, void *data, size_t size)
224 {
225 	struct client_file	 find, *cf;
226 	struct msg_write_open	 msg;
227 
228 	if (!file_can_print(c))
229 		return;
230 
231 	find.stream = 1;
232 	if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
233 		cf = file_create_with_client(c, 1, NULL, NULL);
234 		cf->path = xstrdup("-");
235 
236 		evbuffer_add(cf->buffer, data, size);
237 
238 		msg.stream = 1;
239 		msg.fd = STDOUT_FILENO;
240 		msg.flags = 0;
241 		proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
242 	} else {
243 		evbuffer_add(cf->buffer, data, size);
244 		file_push(cf);
245 	}
246 }
247 
248 /* Report an error to a file. */
249 void
file_error(struct client * c,const char * fmt,...)250 file_error(struct client *c, const char *fmt, ...)
251 {
252 	struct client_file	 find, *cf;
253 	struct msg_write_open	 msg;
254 	va_list			 ap;
255 
256 	if (!file_can_print(c))
257 		return;
258 
259 	va_start(ap, fmt);
260 
261 	find.stream = 2;
262 	if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
263 		cf = file_create_with_client(c, 2, NULL, NULL);
264 		cf->path = xstrdup("-");
265 
266 		evbuffer_add_vprintf(cf->buffer, fmt, ap);
267 
268 		msg.stream = 2;
269 		msg.fd = STDERR_FILENO;
270 		msg.flags = 0;
271 		proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
272 	} else {
273 		evbuffer_add_vprintf(cf->buffer, fmt, ap);
274 		file_push(cf);
275 	}
276 
277 	va_end(ap);
278 }
279 
280 /* Write data to a file. */
281 void
file_write(struct client * c,const char * path,int flags,const void * bdata,size_t bsize,client_file_cb cb,void * cbdata)282 file_write(struct client *c, const char *path, int flags, const void *bdata,
283     size_t bsize, client_file_cb cb, void *cbdata)
284 {
285 	struct client_file	*cf;
286 	struct msg_write_open	*msg;
287 	size_t			 msglen;
288 	int			 fd = -1;
289 	u_int			 stream = file_next_stream++;
290 	FILE			*f;
291 	const char		*mode;
292 
293 	if (strcmp(path, "-") == 0) {
294 		cf = file_create_with_client(c, stream, cb, cbdata);
295 		cf->path = xstrdup("-");
296 
297 		fd = STDOUT_FILENO;
298 		if (c == NULL ||
299 		    (c->flags & CLIENT_ATTACHED) ||
300 		    (c->flags & CLIENT_CONTROL)) {
301 			cf->error = EBADF;
302 			goto done;
303 		}
304 		goto skip;
305 	}
306 
307 	cf = file_create_with_client(c, stream, cb, cbdata);
308 	cf->path = file_get_path(c, path);
309 
310 	if (c == NULL || c->flags & CLIENT_ATTACHED) {
311 		if (flags & O_APPEND)
312 			mode = "ab";
313 		else
314 			mode = "wb";
315 		f = fopen(cf->path, mode);
316 		if (f == NULL) {
317 			cf->error = errno;
318 			goto done;
319 		}
320 		if (fwrite(bdata, 1, bsize, f) != bsize) {
321 			fclose(f);
322 			cf->error = EIO;
323 			goto done;
324 		}
325 		fclose(f);
326 		goto done;
327 	}
328 
329 skip:
330 	evbuffer_add(cf->buffer, bdata, bsize);
331 
332 	msglen = strlen(cf->path) + 1 + sizeof *msg;
333 	if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
334 		cf->error = E2BIG;
335 		goto done;
336 	}
337 	msg = xmalloc(msglen);
338 	msg->stream = cf->stream;
339 	msg->fd = fd;
340 	msg->flags = flags;
341 	memcpy(msg + 1, cf->path, msglen - sizeof *msg);
342 	if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) {
343 		free(msg);
344 		cf->error = EINVAL;
345 		goto done;
346 	}
347 	free(msg);
348 	return;
349 
350 done:
351 	file_fire_done(cf);
352 }
353 
354 /* Read a file. */
355 void
file_read(struct client * c,const char * path,client_file_cb cb,void * cbdata)356 file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
357 {
358 	struct client_file	*cf;
359 	struct msg_read_open	*msg;
360 	size_t			 msglen;
361 	int			 fd = -1;
362 	u_int			 stream = file_next_stream++;
363 	FILE			*f;
364 	size_t			 size;
365 	char			 buffer[BUFSIZ];
366 
367 	if (strcmp(path, "-") == 0) {
368 		cf = file_create_with_client(c, stream, cb, cbdata);
369 		cf->path = xstrdup("-");
370 
371 		fd = STDIN_FILENO;
372 		if (c == NULL ||
373 		    (c->flags & CLIENT_ATTACHED) ||
374 		    (c->flags & CLIENT_CONTROL)) {
375 			cf->error = EBADF;
376 			goto done;
377 		}
378 		goto skip;
379 	}
380 
381 	cf = file_create_with_client(c, stream, cb, cbdata);
382 	cf->path = file_get_path(c, path);
383 
384 	if (c == NULL || c->flags & CLIENT_ATTACHED) {
385 		f = fopen(cf->path, "rb");
386 		if (f == NULL) {
387 			cf->error = errno;
388 			goto done;
389 		}
390 		for (;;) {
391 			size = fread(buffer, 1, sizeof buffer, f);
392 			if (evbuffer_add(cf->buffer, buffer, size) != 0) {
393 				cf->error = ENOMEM;
394 				goto done;
395 			}
396 			if (size != sizeof buffer)
397 				break;
398 		}
399 		if (ferror(f)) {
400 			cf->error = EIO;
401 			goto done;
402 		}
403 		fclose(f);
404 		goto done;
405 	}
406 
407 skip:
408 	msglen = strlen(cf->path) + 1 + sizeof *msg;
409 	if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
410 		cf->error = E2BIG;
411 		goto done;
412 	}
413 	msg = xmalloc(msglen);
414 	msg->stream = cf->stream;
415 	msg->fd = fd;
416 	memcpy(msg + 1, cf->path, msglen - sizeof *msg);
417 	if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) {
418 		free(msg);
419 		cf->error = EINVAL;
420 		goto done;
421 	}
422 	free(msg);
423 	return;
424 
425 done:
426 	file_fire_done(cf);
427 }
428 
429 /* Push event, fired if there is more writing to be done. */
430 static void
file_push_cb(__unused int fd,__unused short events,void * arg)431 file_push_cb(__unused int fd, __unused short events, void *arg)
432 {
433 	struct client_file	*cf = arg;
434 
435 	if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD)
436 		file_push(cf);
437 	file_free(cf);
438 }
439 
440 /* Push uwritten data to the client for a file, if it will accept it. */
441 void
file_push(struct client_file * cf)442 file_push(struct client_file *cf)
443 {
444 	struct msg_write_data	*msg;
445 	size_t			 msglen, sent, left;
446 	struct msg_write_close	 close;
447 
448 	msg = xmalloc(sizeof *msg);
449 	left = EVBUFFER_LENGTH(cf->buffer);
450 	while (left != 0) {
451 		sent = left;
452 		if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
453 			sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
454 
455 		msglen = (sizeof *msg) + sent;
456 		msg = xrealloc(msg, msglen);
457 		msg->stream = cf->stream;
458 		memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent);
459 		if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0)
460 			break;
461 		evbuffer_drain(cf->buffer, sent);
462 
463 		left = EVBUFFER_LENGTH(cf->buffer);
464 		log_debug("file %d sent %zu, left %zu", cf->stream, sent, left);
465 	}
466 	if (left != 0) {
467 		cf->references++;
468 		event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL);
469 	} else if (cf->stream > 2) {
470 		close.stream = cf->stream;
471 		proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close);
472 		file_fire_done(cf);
473 	}
474 	free(msg);
475 }
476 
477 /* Check if any files have data left to write. */
478 int
file_write_left(struct client_files * files)479 file_write_left(struct client_files *files)
480 {
481 	struct client_file	*cf;
482 	size_t			 left;
483 	int			 waiting = 0;
484 
485 	RB_FOREACH(cf, client_files, files) {
486 		if (cf->event == NULL)
487 			continue;
488 		left = EVBUFFER_LENGTH(cf->event->output);
489 		if (left != 0) {
490 			waiting++;
491 			log_debug("file %u %zu bytes left", cf->stream, left);
492 		}
493 	}
494 	return (waiting != 0);
495 }
496 
497 /* Client file write error callback. */
498 static void
file_write_error_callback(__unused struct bufferevent * bev,__unused short what,void * arg)499 file_write_error_callback(__unused struct bufferevent *bev, __unused short what,
500     void *arg)
501 {
502 	struct client_file	*cf = arg;
503 
504 	log_debug("write error file %d", cf->stream);
505 
506 	bufferevent_free(cf->event);
507 	cf->event = NULL;
508 
509 	close(cf->fd);
510 	cf->fd = -1;
511 
512 	if (cf->cb != NULL)
513 		cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
514 }
515 
516 /* Client file write callback. */
517 static void
file_write_callback(__unused struct bufferevent * bev,void * arg)518 file_write_callback(__unused struct bufferevent *bev, void *arg)
519 {
520 	struct client_file	*cf = arg;
521 
522 	log_debug("write check file %d", cf->stream);
523 
524 	if (cf->cb != NULL)
525 		cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
526 
527 	if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
528 		bufferevent_free(cf->event);
529 		close(cf->fd);
530 		RB_REMOVE(client_files, cf->tree, cf);
531 		file_free(cf);
532 	}
533 }
534 
535 /* Handle a file write open message (client). */
536 void
file_write_open(struct client_files * files,struct tmuxpeer * peer,struct imsg * imsg,int allow_streams,int close_received,client_file_cb cb,void * cbdata)537 file_write_open(struct client_files *files, struct tmuxpeer *peer,
538     struct imsg *imsg, int allow_streams, int close_received,
539     client_file_cb cb, void *cbdata)
540 {
541 	struct msg_write_open	*msg = imsg->data;
542 	size_t			 msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
543 	const char		*path;
544 	struct msg_write_ready	 reply;
545 	struct client_file	 find, *cf;
546 	const int		 flags = O_NONBLOCK|O_WRONLY|O_CREAT;
547 	int			 error = 0;
548 
549 	if (msglen < sizeof *msg)
550 		fatalx("bad MSG_WRITE_OPEN size");
551 	if (msglen == sizeof *msg)
552 		path = "-";
553 	else
554 		path = (const char *)(msg + 1);
555 	log_debug("open write file %d %s", msg->stream, path);
556 
557 	find.stream = msg->stream;
558 	if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
559 		error = EBADF;
560 		goto reply;
561 	}
562 	cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
563 	if (cf->closed) {
564 		error = EBADF;
565 		goto reply;
566 	}
567 
568 	cf->fd = -1;
569 	if (msg->fd == -1)
570 		cf->fd = open(path, msg->flags|flags, 0644);
571 	else if (allow_streams) {
572 		if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
573 			errno = EBADF;
574 		else {
575 			cf->fd = dup(msg->fd);
576 			if (close_received)
577 				close(msg->fd); /* can only be used once */
578 		}
579 	} else
580 	      errno = EBADF;
581 	if (cf->fd == -1) {
582 		error = errno;
583 		goto reply;
584 	}
585 
586 	cf->event = bufferevent_new(cf->fd, NULL, file_write_callback,
587 	    file_write_error_callback, cf);
588 	bufferevent_enable(cf->event, EV_WRITE);
589 	goto reply;
590 
591 reply:
592 	reply.stream = msg->stream;
593 	reply.error = error;
594 	proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
595 }
596 
597 /* Handle a file write data message (client). */
598 void
file_write_data(struct client_files * files,struct imsg * imsg)599 file_write_data(struct client_files *files, struct imsg *imsg)
600 {
601 	struct msg_write_data	*msg = imsg->data;
602 	size_t			 msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
603 	struct client_file	 find, *cf;
604 	size_t			 size = msglen - sizeof *msg;
605 
606 	if (msglen < sizeof *msg)
607 		fatalx("bad MSG_WRITE size");
608 	find.stream = msg->stream;
609 	if ((cf = RB_FIND(client_files, files, &find)) == NULL)
610 		fatalx("unknown stream number");
611 	log_debug("write %zu to file %d", size, cf->stream);
612 
613 	if (cf->event != NULL)
614 		bufferevent_write(cf->event, msg + 1, size);
615 }
616 
617 /* Handle a file write close message (client). */
618 void
file_write_close(struct client_files * files,struct imsg * imsg)619 file_write_close(struct client_files *files, struct imsg *imsg)
620 {
621 	struct msg_write_close	*msg = imsg->data;
622 	size_t			 msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
623 	struct client_file	 find, *cf;
624 
625 	if (msglen != sizeof *msg)
626 		fatalx("bad MSG_WRITE_CLOSE size");
627 	find.stream = msg->stream;
628 	if ((cf = RB_FIND(client_files, files, &find)) == NULL)
629 		fatalx("unknown stream number");
630 	log_debug("close file %d", cf->stream);
631 
632 	if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
633 		if (cf->event != NULL)
634 			bufferevent_free(cf->event);
635 		if (cf->fd != -1)
636 			close(cf->fd);
637 		RB_REMOVE(client_files, files, cf);
638 		file_free(cf);
639 	}
640 }
641 
642 /* Client file read error callback. */
643 static void
file_read_error_callback(__unused struct bufferevent * bev,__unused short what,void * arg)644 file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
645     void *arg)
646 {
647 	struct client_file	*cf = arg;
648 	struct msg_read_done	 msg;
649 
650 	log_debug("read error file %d", cf->stream);
651 
652 	msg.stream = cf->stream;
653 	msg.error = 0;
654 	proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
655 
656 	bufferevent_free(cf->event);
657 	close(cf->fd);
658 	RB_REMOVE(client_files, cf->tree, cf);
659 	file_free(cf);
660 }
661 
662 /* Client file read callback. */
663 static void
file_read_callback(__unused struct bufferevent * bev,void * arg)664 file_read_callback(__unused struct bufferevent *bev, void *arg)
665 {
666 	struct client_file	*cf = arg;
667 	void			*bdata;
668 	size_t			 bsize;
669 	struct msg_read_data	*msg;
670 	size_t			 msglen;
671 
672 	msg = xmalloc(sizeof *msg);
673 	for (;;) {
674 		bdata = EVBUFFER_DATA(cf->event->input);
675 		bsize = EVBUFFER_LENGTH(cf->event->input);
676 
677 		if (bsize == 0)
678 			break;
679 		if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
680 			bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
681 		log_debug("read %zu from file %d", bsize, cf->stream);
682 
683 		msglen = (sizeof *msg) + bsize;
684 		msg = xrealloc(msg, msglen);
685 		msg->stream = cf->stream;
686 		memcpy(msg + 1, bdata, bsize);
687 		proc_send(cf->peer, MSG_READ, -1, msg, msglen);
688 
689 		evbuffer_drain(cf->event->input, bsize);
690 	}
691 	free(msg);
692 }
693 
694 /* Handle a file read open message (client). */
695 void
file_read_open(struct client_files * files,struct tmuxpeer * peer,struct imsg * imsg,int allow_streams,int close_received,client_file_cb cb,void * cbdata)696 file_read_open(struct client_files *files, struct tmuxpeer *peer,
697     struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb,
698     void *cbdata)
699 {
700 	struct msg_read_open	*msg = imsg->data;
701 	size_t			 msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
702 	const char		*path;
703 	struct msg_read_done	 reply;
704 	struct client_file	 find, *cf;
705 	const int		 flags = O_NONBLOCK|O_RDONLY;
706 	int			 error;
707 
708 	if (msglen < sizeof *msg)
709 		fatalx("bad MSG_READ_OPEN size");
710 	if (msglen == sizeof *msg)
711 		path = "-";
712 	else
713 		path = (const char *)(msg + 1);
714 	log_debug("open read file %d %s", msg->stream, path);
715 
716 	find.stream = msg->stream;
717 	if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
718 		error = EBADF;
719 		goto reply;
720 	}
721 	cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
722 	if (cf->closed) {
723 		error = EBADF;
724 		goto reply;
725 	}
726 
727 	cf->fd = -1;
728 	if (msg->fd == -1)
729 		cf->fd = open(path, flags);
730 	else if (allow_streams) {
731 		if (msg->fd != STDIN_FILENO)
732 			errno = EBADF;
733 		else {
734 			cf->fd = dup(msg->fd);
735 			if (close_received)
736 				close(msg->fd); /* can only be used once */
737 		}
738 	} else
739 		errno = EBADF;
740 	if (cf->fd == -1) {
741 		error = errno;
742 		goto reply;
743 	}
744 
745 	cf->event = bufferevent_new(cf->fd, file_read_callback, NULL,
746 	    file_read_error_callback, cf);
747 	bufferevent_enable(cf->event, EV_READ);
748 	return;
749 
750 reply:
751 	reply.stream = msg->stream;
752 	reply.error = error;
753 	proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
754 }
755 
756 /* Handle a write ready message (server). */
757 void
file_write_ready(struct client_files * files,struct imsg * imsg)758 file_write_ready(struct client_files *files, struct imsg *imsg)
759 {
760 	struct msg_write_ready	*msg = imsg->data;
761 	size_t			 msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
762 	struct client_file	 find, *cf;
763 
764 	if (msglen != sizeof *msg)
765 		fatalx("bad MSG_WRITE_READY size");
766 	find.stream = msg->stream;
767 	if ((cf = RB_FIND(client_files, files, &find)) == NULL)
768 		return;
769 	if (msg->error != 0) {
770 		cf->error = msg->error;
771 		file_fire_done(cf);
772 	} else
773 		file_push(cf);
774 }
775 
776 /* Handle read data message (server). */
777 void
file_read_data(struct client_files * files,struct imsg * imsg)778 file_read_data(struct client_files *files, struct imsg *imsg)
779 {
780 	struct msg_read_data	*msg = imsg->data;
781 	size_t			 msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
782 	struct client_file	 find, *cf;
783 	void			*bdata = msg + 1;
784 	size_t			 bsize = msglen - sizeof *msg;
785 
786 	if (msglen < sizeof *msg)
787 		fatalx("bad MSG_READ_DATA size");
788 	find.stream = msg->stream;
789 	if ((cf = RB_FIND(client_files, files, &find)) == NULL)
790 		return;
791 
792 	log_debug("file %d read %zu bytes", cf->stream, bsize);
793 	if (cf->error == 0) {
794 		if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
795 			cf->error = ENOMEM;
796 			file_fire_done(cf);
797 		} else
798 			file_fire_read(cf);
799 	}
800 }
801 
802 /* Handle a read done message (server). */
803 void
file_read_done(struct client_files * files,struct imsg * imsg)804 file_read_done(struct client_files *files, struct imsg *imsg)
805 {
806 	struct msg_read_done	*msg = imsg->data;
807 	size_t			 msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
808 	struct client_file	 find, *cf;
809 
810 	if (msglen != sizeof *msg)
811 		fatalx("bad MSG_READ_DONE size");
812 	find.stream = msg->stream;
813 	if ((cf = RB_FIND(client_files, files, &find)) == NULL)
814 		return;
815 
816 	log_debug("file %d read done", cf->stream);
817 	cf->error = msg->error;
818 	file_fire_done(cf);
819 }
820