Fix use-after-free of the window link when it is part of a grouped
[tmux-openbsd.git] / server-client.c
blob03d5c84b4478e792491b5f84e101572dad449113
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <event.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <time.h>
25 #include <paths.h>
26 #include <unistd.h>
28 #include "tmux.h"
30 void server_client_handle_key(int, struct mouse_event *, void *);
31 void server_client_repeat_timer(int, short, void *);
32 void server_client_check_redraw(struct client *);
33 void server_client_set_title(struct client *);
34 void server_client_reset_state(struct client *);
36 int server_client_msg_dispatch(struct client *);
37 void server_client_msg_command(struct client *, struct msg_command_data *);
38 void server_client_msg_identify(
39 struct client *, struct msg_identify_data *, int);
40 void server_client_msg_shell(struct client *);
42 void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...);
43 void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...);
44 void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...);
46 /* Create a new client. */
47 void
48 server_client_create(int fd)
50 struct client *c;
51 int mode;
52 u_int i;
54 if ((mode = fcntl(fd, F_GETFL)) == -1)
55 fatal("fcntl failed");
56 if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
57 fatal("fcntl failed");
58 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
59 fatal("fcntl failed");
61 c = xcalloc(1, sizeof *c);
62 c->references = 0;
63 imsg_init(&c->ibuf, fd);
64 server_update_event(c);
66 if (gettimeofday(&c->creation_time, NULL) != 0)
67 fatal("gettimeofday failed");
68 memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
70 ARRAY_INIT(&c->prompt_hdata);
72 c->tty.fd = -1;
73 c->title = NULL;
75 c->session = NULL;
76 c->tty.sx = 80;
77 c->tty.sy = 24;
79 screen_init(&c->status, c->tty.sx, 1, 0);
80 job_tree_init(&c->status_jobs);
82 c->message_string = NULL;
83 ARRAY_INIT(&c->message_log);
85 c->prompt_string = NULL;
86 c->prompt_buffer = NULL;
87 c->prompt_index = 0;
89 evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
91 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
92 if (ARRAY_ITEM(&clients, i) == NULL) {
93 ARRAY_SET(&clients, i, c);
94 return;
97 ARRAY_ADD(&clients, c);
98 log_debug("new client %d", fd);
101 /* Lost a client. */
102 void
103 server_client_lost(struct client *c)
105 struct message_entry *msg;
106 u_int i;
108 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
109 if (ARRAY_ITEM(&clients, i) == c)
110 ARRAY_SET(&clients, i, NULL);
112 log_debug("lost client %d", c->ibuf.fd);
115 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
116 * and tty_free might close an unrelated fd.
118 if (c->flags & CLIENT_TERMINAL)
119 tty_free(&c->tty);
121 screen_free(&c->status);
122 job_tree_free(&c->status_jobs);
124 if (c->title != NULL)
125 xfree(c->title);
127 evtimer_del(&c->repeat_timer);
129 evtimer_del(&c->identify_timer);
131 if (c->message_string != NULL)
132 xfree(c->message_string);
133 evtimer_del(&c->message_timer);
134 for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) {
135 msg = &ARRAY_ITEM(&c->message_log, i);
136 xfree(msg->msg);
138 ARRAY_FREE(&c->message_log);
140 if (c->prompt_string != NULL)
141 xfree(c->prompt_string);
142 if (c->prompt_buffer != NULL)
143 xfree(c->prompt_buffer);
144 for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
145 xfree(ARRAY_ITEM(&c->prompt_hdata, i));
146 ARRAY_FREE(&c->prompt_hdata);
148 if (c->cwd != NULL)
149 xfree(c->cwd);
151 close(c->ibuf.fd);
152 imsg_clear(&c->ibuf);
153 event_del(&c->event);
155 for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
156 if (ARRAY_ITEM(&dead_clients, i) == NULL) {
157 ARRAY_SET(&dead_clients, i, c);
158 break;
161 if (i == ARRAY_LENGTH(&dead_clients))
162 ARRAY_ADD(&dead_clients, c);
163 c->flags |= CLIENT_DEAD;
165 recalculate_sizes();
166 server_update_socket();
169 /* Process a single client event. */
170 void
171 server_client_callback(int fd, short events, void *data)
173 struct client *c = data;
175 if (c->flags & CLIENT_DEAD)
176 return;
178 if (fd == c->ibuf.fd) {
179 if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0)
180 goto client_lost;
182 if (c->flags & CLIENT_BAD) {
183 if (c->ibuf.w.queued == 0)
184 goto client_lost;
185 return;
188 if (events & EV_READ && server_client_msg_dispatch(c) != 0)
189 goto client_lost;
192 server_update_event(c);
193 return;
195 client_lost:
196 server_client_lost(c);
199 /* Handle client status timer. */
200 void
201 server_client_status_timer(void)
203 struct client *c;
204 struct session *s;
205 struct job *job;
206 struct timeval tv;
207 u_int i;
208 int interval;
209 time_t difference;
211 if (gettimeofday(&tv, NULL) != 0)
212 fatal("gettimeofday failed");
214 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
215 c = ARRAY_ITEM(&clients, i);
216 if (c == NULL || c->session == NULL)
217 continue;
218 if (c->message_string != NULL || c->prompt_string != NULL) {
220 * Don't need timed redraw for messages/prompts so bail
221 * now. The status timer isn't reset when they are
222 * redrawn anyway.
224 continue;
226 s = c->session;
228 if (!options_get_number(&s->options, "status"))
229 continue;
230 interval = options_get_number(&s->options, "status-interval");
232 difference = tv.tv_sec - c->status_timer.tv_sec;
233 if (difference >= interval) {
234 RB_FOREACH(job, jobs, &c->status_jobs)
235 job_run(job);
236 c->flags |= CLIENT_STATUS;
241 /* Handle data key input from client. */
242 void
243 server_client_handle_key(int key, struct mouse_event *mouse, void *data)
245 struct client *c = data;
246 struct session *s;
247 struct window *w;
248 struct window_pane *wp;
249 struct options *oo;
250 struct timeval tv;
251 struct key_binding *bd;
252 struct keylist *keylist;
253 int xtimeout, isprefix;
254 u_int i;
256 /* Check the client is good to accept input. */
257 if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
258 return;
259 if (c->session == NULL)
260 return;
261 s = c->session;
263 /* Update the activity timer. */
264 if (gettimeofday(&c->activity_time, NULL) != 0)
265 fatal("gettimeofday failed");
266 memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time);
268 w = c->session->curw->window;
269 wp = w->active;
270 oo = &c->session->options;
272 /* Special case: number keys jump to pane in identify mode. */
273 if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
274 if (c->flags & CLIENT_READONLY)
275 return;
276 wp = window_pane_at_index(w, key - '0');
277 if (wp != NULL && window_pane_visible(wp))
278 window_set_active_pane(w, wp);
279 server_clear_identify(c);
280 return;
283 /* Handle status line. */
284 if (!(c->flags & CLIENT_READONLY)) {
285 status_message_clear(c);
286 server_clear_identify(c);
288 if (c->prompt_string != NULL) {
289 if (!(c->flags & CLIENT_READONLY))
290 status_prompt_key(c, key);
291 return;
294 /* Check for mouse keys. */
295 if (key == KEYC_MOUSE) {
296 if (c->flags & CLIENT_READONLY)
297 return;
298 if (options_get_number(oo, "mouse-select-pane")) {
299 window_set_active_at(w, mouse->x, mouse->y);
300 server_redraw_window_borders(w);
301 wp = w->active;
303 window_pane_mouse(wp, c, mouse);
304 return;
307 /* Is this a prefix key? */
308 keylist = options_get_data(&c->session->options, "prefix");
309 isprefix = 0;
310 for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
311 if (key == ARRAY_ITEM(keylist, i)) {
312 isprefix = 1;
313 break;
317 /* No previous prefix key. */
318 if (!(c->flags & CLIENT_PREFIX)) {
319 if (isprefix)
320 c->flags |= CLIENT_PREFIX;
321 else {
322 /* Try as a non-prefix key binding. */
323 if ((bd = key_bindings_lookup(key)) == NULL) {
324 if (!(c->flags & CLIENT_READONLY))
325 window_pane_key(wp, c, key);
326 } else
327 key_bindings_dispatch(bd, c);
329 return;
332 /* Prefix key already pressed. Reset prefix and lookup key. */
333 c->flags &= ~CLIENT_PREFIX;
334 if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
335 /* If repeating, treat this as a key, else ignore. */
336 if (c->flags & CLIENT_REPEAT) {
337 c->flags &= ~CLIENT_REPEAT;
338 if (isprefix)
339 c->flags |= CLIENT_PREFIX;
340 else if (!(c->flags & CLIENT_READONLY))
341 window_pane_key(wp, c, key);
343 return;
346 /* If already repeating, but this key can't repeat, skip it. */
347 if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
348 c->flags &= ~CLIENT_REPEAT;
349 if (isprefix)
350 c->flags |= CLIENT_PREFIX;
351 else if (!(c->flags & CLIENT_READONLY))
352 window_pane_key(wp, c, key);
353 return;
356 /* If this key can repeat, reset the repeat flags and timer. */
357 xtimeout = options_get_number(&c->session->options, "repeat-time");
358 if (xtimeout != 0 && bd->can_repeat) {
359 c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
361 tv.tv_sec = xtimeout / 1000;
362 tv.tv_usec = (xtimeout % 1000) * 1000L;
363 evtimer_del(&c->repeat_timer);
364 evtimer_add(&c->repeat_timer, &tv);
367 /* Dispatch the command. */
368 key_bindings_dispatch(bd, c);
371 /* Client functions that need to happen every loop. */
372 void
373 server_client_loop(void)
375 struct client *c;
376 struct window *w;
377 struct window_pane *wp;
378 u_int i;
380 for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
381 c = ARRAY_ITEM(&clients, i);
382 if (c == NULL || c->session == NULL)
383 continue;
385 server_client_check_redraw(c);
386 server_client_reset_state(c);
390 * Any windows will have been redrawn as part of clients, so clear
391 * their flags now.
393 for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
394 w = ARRAY_ITEM(&windows, i);
395 if (w == NULL)
396 continue;
398 w->flags &= ~WINDOW_REDRAW;
399 TAILQ_FOREACH(wp, &w->panes, entry)
400 wp->flags &= ~PANE_REDRAW;
405 * Update cursor position and mode settings. The scroll region and attributes
406 * are cleared when idle (waiting for an event) as this is the most likely time
407 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
408 * compromise between excessive resets and likelihood of an interrupt.
410 * tty_region/tty_reset/tty_update_mode already take care of not resetting
411 * things that are already in their default state.
413 void
414 server_client_reset_state(struct client *c)
416 struct window *w = c->session->curw->window;
417 struct window_pane *wp = w->active;
418 struct screen *s = wp->screen;
419 struct options *oo = &c->session->options;
420 int status, mode;
422 tty_region(&c->tty, 0, c->tty.sy - 1);
424 status = options_get_number(oo, "status");
425 if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
426 tty_cursor(&c->tty, 0, 0);
427 else
428 tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy);
430 mode = s->mode;
431 if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL &&
432 options_get_number(oo, "mouse-select-pane"))
433 mode |= MODE_MOUSE;
434 tty_update_mode(&c->tty, mode);
435 tty_reset(&c->tty);
438 /* Repeat time callback. */
439 /* ARGSUSED */
440 void
441 server_client_repeat_timer(unused int fd, unused short events, void *data)
443 struct client *c = data;
445 if (c->flags & CLIENT_REPEAT)
446 c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
449 /* Check for client redraws. */
450 void
451 server_client_check_redraw(struct client *c)
453 struct session *s = c->session;
454 struct window_pane *wp;
455 int flags, redraw;
457 flags = c->tty.flags & TTY_FREEZE;
458 c->tty.flags &= ~TTY_FREEZE;
460 if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
461 if (options_get_number(&s->options, "set-titles"))
462 server_client_set_title(c);
464 if (c->message_string != NULL)
465 redraw = status_message_redraw(c);
466 else if (c->prompt_string != NULL)
467 redraw = status_prompt_redraw(c);
468 else
469 redraw = status_redraw(c);
470 if (!redraw)
471 c->flags &= ~CLIENT_STATUS;
474 if (c->flags & CLIENT_REDRAW) {
475 screen_redraw_screen(c, 0, 0);
476 c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
477 } else {
478 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
479 if (wp->flags & PANE_REDRAW)
480 screen_redraw_pane(c, wp);
484 if (c->flags & CLIENT_BORDERS)
485 screen_redraw_screen(c, 0, 1);
487 if (c->flags & CLIENT_STATUS)
488 screen_redraw_screen(c, 1, 0);
490 c->tty.flags |= flags;
492 c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS);
495 /* Set client title. */
496 void
497 server_client_set_title(struct client *c)
499 struct session *s = c->session;
500 const char *template;
501 char *title;
503 template = options_get_string(&s->options, "set-titles-string");
505 title = status_replace(c, NULL, template, time(NULL), 1);
506 if (c->title == NULL || strcmp(title, c->title) != 0) {
507 if (c->title != NULL)
508 xfree(c->title);
509 c->title = xstrdup(title);
510 tty_set_title(&c->tty, c->title);
512 xfree(title);
515 /* Dispatch message from client. */
517 server_client_msg_dispatch(struct client *c)
519 struct imsg imsg;
520 struct msg_command_data commanddata;
521 struct msg_identify_data identifydata;
522 struct msg_environ_data environdata;
523 ssize_t n, datalen;
525 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
526 return (-1);
528 for (;;) {
529 if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
530 return (-1);
531 if (n == 0)
532 return (0);
533 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
535 if (imsg.hdr.peerid != PROTOCOL_VERSION) {
536 server_write_client(c, MSG_VERSION, NULL, 0);
537 c->flags |= CLIENT_BAD;
538 imsg_free(&imsg);
539 continue;
542 log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
543 switch (imsg.hdr.type) {
544 case MSG_COMMAND:
545 if (datalen != sizeof commanddata)
546 fatalx("bad MSG_COMMAND size");
547 memcpy(&commanddata, imsg.data, sizeof commanddata);
549 server_client_msg_command(c, &commanddata);
550 break;
551 case MSG_IDENTIFY:
552 if (datalen != sizeof identifydata)
553 fatalx("bad MSG_IDENTIFY size");
554 if (imsg.fd == -1)
555 fatalx("MSG_IDENTIFY missing fd");
556 memcpy(&identifydata, imsg.data, sizeof identifydata);
558 server_client_msg_identify(c, &identifydata, imsg.fd);
559 break;
560 case MSG_RESIZE:
561 if (datalen != 0)
562 fatalx("bad MSG_RESIZE size");
564 tty_resize(&c->tty);
565 recalculate_sizes();
566 server_redraw_client(c);
567 break;
568 case MSG_EXITING:
569 if (datalen != 0)
570 fatalx("bad MSG_EXITING size");
572 c->session = NULL;
573 tty_close(&c->tty);
574 server_write_client(c, MSG_EXITED, NULL, 0);
575 break;
576 case MSG_WAKEUP:
577 case MSG_UNLOCK:
578 if (datalen != 0)
579 fatalx("bad MSG_WAKEUP size");
581 if (!(c->flags & CLIENT_SUSPENDED))
582 break;
583 c->flags &= ~CLIENT_SUSPENDED;
585 if (gettimeofday(&c->activity_time, NULL) != 0)
586 fatal("gettimeofday");
587 if (c->session != NULL) {
588 memcpy(&c->session->activity_time,
589 &c->activity_time,
590 sizeof c->session->activity_time);
593 tty_start_tty(&c->tty);
594 server_redraw_client(c);
595 recalculate_sizes();
596 break;
597 case MSG_ENVIRON:
598 if (datalen != sizeof environdata)
599 fatalx("bad MSG_ENVIRON size");
600 memcpy(&environdata, imsg.data, sizeof environdata);
602 environdata.var[(sizeof environdata.var) - 1] = '\0';
603 if (strchr(environdata.var, '=') != NULL)
604 environ_put(&c->environ, environdata.var);
605 break;
606 case MSG_SHELL:
607 if (datalen != 0)
608 fatalx("bad MSG_SHELL size");
610 server_client_msg_shell(c);
611 break;
612 default:
613 fatalx("unexpected message");
616 imsg_free(&imsg);
620 /* Callback to send error message to client. */
621 void printflike2
622 server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
624 struct msg_print_data data;
625 va_list ap;
627 va_start(ap, fmt);
628 xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
629 va_end(ap);
631 server_write_client(ctx->cmdclient, MSG_ERROR, &data, sizeof data);
634 /* Callback to send print message to client. */
635 void printflike2
636 server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
638 struct msg_print_data data;
639 va_list ap;
641 va_start(ap, fmt);
642 xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
643 va_end(ap);
645 server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
648 /* Callback to send print message to client, if not quiet. */
649 void printflike2
650 server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
652 struct msg_print_data data;
653 va_list ap;
655 if (options_get_number(&global_options, "quiet"))
656 return;
658 va_start(ap, fmt);
659 xvsnprintf(data.msg, sizeof data.msg, fmt, ap);
660 va_end(ap);
662 server_write_client(ctx->cmdclient, MSG_PRINT, &data, sizeof data);
665 /* Handle command message. */
666 void
667 server_client_msg_command(struct client *c, struct msg_command_data *data)
669 struct cmd_ctx ctx;
670 struct cmd_list *cmdlist = NULL;
671 int argc;
672 char **argv, *cause;
674 ctx.error = server_client_msg_error;
675 ctx.print = server_client_msg_print;
676 ctx.info = server_client_msg_info;
678 ctx.msgdata = data;
679 ctx.curclient = NULL;
681 ctx.cmdclient = c;
683 argc = data->argc;
684 data->argv[(sizeof data->argv) - 1] = '\0';
685 if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) {
686 server_client_msg_error(&ctx, "command too long");
687 goto error;
690 if (argc == 0) {
691 argc = 1;
692 argv = xcalloc(1, sizeof *argv);
693 *argv = xstrdup("new-session");
696 if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
697 server_client_msg_error(&ctx, "%s", cause);
698 cmd_free_argv(argc, argv);
699 goto error;
701 cmd_free_argv(argc, argv);
703 if (cmd_list_exec(cmdlist, &ctx) != 1)
704 server_write_client(c, MSG_EXIT, NULL, 0);
705 cmd_list_free(cmdlist);
706 return;
708 error:
709 if (cmdlist != NULL)
710 cmd_list_free(cmdlist);
711 server_write_client(c, MSG_EXIT, NULL, 0);
714 /* Handle identify message. */
715 void
716 server_client_msg_identify(
717 struct client *c, struct msg_identify_data *data, int fd)
719 c->cwd = NULL;
720 data->cwd[(sizeof data->cwd) - 1] = '\0';
721 if (*data->cwd != '\0')
722 c->cwd = xstrdup(data->cwd);
724 data->term[(sizeof data->term) - 1] = '\0';
725 tty_init(&c->tty, fd, data->term);
726 if (data->flags & IDENTIFY_UTF8)
727 c->tty.flags |= TTY_UTF8;
728 if (data->flags & IDENTIFY_256COLOURS)
729 c->tty.term_flags |= TERM_256COLOURS;
730 else if (data->flags & IDENTIFY_88COLOURS)
731 c->tty.term_flags |= TERM_88COLOURS;
732 c->tty.key_callback = server_client_handle_key;
733 c->tty.key_data = c;
735 tty_resize(&c->tty);
737 c->flags |= CLIENT_TERMINAL;
740 /* Handle shell message. */
741 void
742 server_client_msg_shell(struct client *c)
744 struct msg_shell_data data;
745 const char *shell;
747 shell = options_get_string(&global_s_options, "default-shell");
749 if (*shell == '\0' || areshell(shell))
750 shell = _PATH_BSHELL;
751 if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell)
752 strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell);
754 server_write_client(c, MSG_SHELL, &data, sizeof data);
755 c->flags |= CLIENT_BAD; /* it will die after exec */