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