1 /* $OpenBSD: server-client.c,v 1.60 2011/07/08 21:51:40 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> 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 <event.h> 22 #include <fcntl.h> 23 #include <string.h> 24 #include <time.h> 25 #include <paths.h> 26 #include <unistd.h> 27 28 #include "tmux.h" 29 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_exit(struct client *); 33 void server_client_check_backoff(struct client *); 34 void server_client_check_redraw(struct client *); 35 void server_client_set_title(struct client *); 36 void server_client_reset_state(struct client *); 37 void server_client_in_callback(struct bufferevent *, short, void *); 38 void server_client_out_callback(struct bufferevent *, short, void *); 39 void server_client_err_callback(struct bufferevent *, short, void *); 40 41 int server_client_msg_dispatch(struct client *); 42 void server_client_msg_command(struct client *, struct msg_command_data *); 43 void server_client_msg_identify( 44 struct client *, struct msg_identify_data *, int); 45 void server_client_msg_shell(struct client *); 46 47 void printflike2 server_client_msg_error(struct cmd_ctx *, const char *, ...); 48 void printflike2 server_client_msg_print(struct cmd_ctx *, const char *, ...); 49 void printflike2 server_client_msg_info(struct cmd_ctx *, const char *, ...); 50 51 /* Create a new client. */ 52 void 53 server_client_create(int fd) 54 { 55 struct client *c; 56 u_int i; 57 58 setblocking(fd, 0); 59 60 c = xcalloc(1, sizeof *c); 61 c->references = 0; 62 imsg_init(&c->ibuf, fd); 63 server_update_event(c); 64 65 if (gettimeofday(&c->creation_time, NULL) != 0) 66 fatal("gettimeofday failed"); 67 memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time); 68 69 c->stdin_event = NULL; 70 c->stdout_event = NULL; 71 c->stderr_event = NULL; 72 73 c->tty.fd = -1; 74 c->title = NULL; 75 76 c->session = NULL; 77 c->last_session = NULL; 78 c->tty.sx = 80; 79 c->tty.sy = 24; 80 81 screen_init(&c->status, c->tty.sx, 1, 0); 82 RB_INIT(&c->status_new); 83 RB_INIT(&c->status_old); 84 85 c->message_string = NULL; 86 ARRAY_INIT(&c->message_log); 87 88 c->prompt_string = NULL; 89 c->prompt_buffer = NULL; 90 c->prompt_index = 0; 91 92 c->last_mouse.b = MOUSE_UP; 93 c->last_mouse.x = c->last_mouse.y = -1; 94 95 evtimer_set(&c->repeat_timer, server_client_repeat_timer, c); 96 97 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 98 if (ARRAY_ITEM(&clients, i) == NULL) { 99 ARRAY_SET(&clients, i, c); 100 return; 101 } 102 } 103 ARRAY_ADD(&clients, c); 104 log_debug("new client %d", fd); 105 } 106 107 /* Lost a client. */ 108 void 109 server_client_lost(struct client *c) 110 { 111 struct message_entry *msg; 112 u_int i; 113 114 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 115 if (ARRAY_ITEM(&clients, i) == c) 116 ARRAY_SET(&clients, i, NULL); 117 } 118 log_debug("lost client %d", c->ibuf.fd); 119 120 /* 121 * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called 122 * and tty_free might close an unrelated fd. 123 */ 124 if (c->flags & CLIENT_TERMINAL) 125 tty_free(&c->tty); 126 127 if (c->stdin_fd != -1) { 128 setblocking(c->stdin_fd, 1); 129 close(c->stdin_fd); 130 } 131 if (c->stdin_event != NULL) 132 bufferevent_free(c->stdin_event); 133 if (c->stdout_fd != -1) { 134 setblocking(c->stdout_fd, 1); 135 close(c->stdout_fd); 136 } 137 if (c->stdout_event != NULL) 138 bufferevent_free(c->stdout_event); 139 if (c->stderr_fd != -1) { 140 setblocking(c->stderr_fd, 1); 141 close(c->stderr_fd); 142 } 143 if (c->stderr_event != NULL) 144 bufferevent_free(c->stderr_event); 145 146 status_free_jobs(&c->status_new); 147 status_free_jobs(&c->status_old); 148 screen_free(&c->status); 149 150 if (c->title != NULL) 151 xfree(c->title); 152 153 evtimer_del(&c->repeat_timer); 154 155 evtimer_del(&c->identify_timer); 156 157 if (c->message_string != NULL) 158 xfree(c->message_string); 159 evtimer_del(&c->message_timer); 160 for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { 161 msg = &ARRAY_ITEM(&c->message_log, i); 162 xfree(msg->msg); 163 } 164 ARRAY_FREE(&c->message_log); 165 166 if (c->prompt_string != NULL) 167 xfree(c->prompt_string); 168 if (c->prompt_buffer != NULL) 169 xfree(c->prompt_buffer); 170 171 if (c->cwd != NULL) 172 xfree(c->cwd); 173 174 close(c->ibuf.fd); 175 imsg_clear(&c->ibuf); 176 event_del(&c->event); 177 178 for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { 179 if (ARRAY_ITEM(&dead_clients, i) == NULL) { 180 ARRAY_SET(&dead_clients, i, c); 181 break; 182 } 183 } 184 if (i == ARRAY_LENGTH(&dead_clients)) 185 ARRAY_ADD(&dead_clients, c); 186 c->flags |= CLIENT_DEAD; 187 188 recalculate_sizes(); 189 server_check_unattached(); 190 server_update_socket(); 191 } 192 193 /* Process a single client event. */ 194 void 195 server_client_callback(int fd, short events, void *data) 196 { 197 struct client *c = data; 198 199 if (c->flags & CLIENT_DEAD) 200 return; 201 202 if (fd == c->ibuf.fd) { 203 if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0) 204 goto client_lost; 205 206 if (c->flags & CLIENT_BAD) { 207 if (c->ibuf.w.queued == 0) 208 goto client_lost; 209 return; 210 } 211 212 if (events & EV_READ && server_client_msg_dispatch(c) != 0) 213 goto client_lost; 214 } 215 216 server_update_event(c); 217 return; 218 219 client_lost: 220 server_client_lost(c); 221 } 222 223 /* Handle client status timer. */ 224 void 225 server_client_status_timer(void) 226 { 227 struct client *c; 228 struct session *s; 229 struct timeval tv; 230 u_int i; 231 int interval; 232 time_t difference; 233 234 if (gettimeofday(&tv, NULL) != 0) 235 fatal("gettimeofday failed"); 236 237 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 238 c = ARRAY_ITEM(&clients, i); 239 if (c == NULL || c->session == NULL) 240 continue; 241 if (c->message_string != NULL || c->prompt_string != NULL) { 242 /* 243 * Don't need timed redraw for messages/prompts so bail 244 * now. The status timer isn't reset when they are 245 * redrawn anyway. 246 */ 247 continue; 248 } 249 s = c->session; 250 251 if (!options_get_number(&s->options, "status")) 252 continue; 253 interval = options_get_number(&s->options, "status-interval"); 254 255 difference = tv.tv_sec - c->status_timer.tv_sec; 256 if (difference >= interval) { 257 status_update_jobs(c); 258 c->flags |= CLIENT_STATUS; 259 } 260 } 261 } 262 263 /* Handle data key input from client. */ 264 void 265 server_client_handle_key(int key, struct mouse_event *mouse, void *data) 266 { 267 struct client *c = data; 268 struct session *s; 269 struct window *w; 270 struct window_pane *wp; 271 struct options *oo; 272 struct timeval tv; 273 struct key_binding *bd; 274 struct keylist *keylist; 275 int xtimeout, isprefix; 276 u_int i; 277 278 /* Check the client is good to accept input. */ 279 if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) 280 return; 281 if (c->session == NULL) 282 return; 283 s = c->session; 284 285 /* Update the activity timer. */ 286 if (gettimeofday(&c->activity_time, NULL) != 0) 287 fatal("gettimeofday failed"); 288 memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); 289 290 w = c->session->curw->window; 291 wp = w->active; 292 oo = &c->session->options; 293 294 /* Special case: number keys jump to pane in identify mode. */ 295 if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { 296 if (c->flags & CLIENT_READONLY) 297 return; 298 wp = window_pane_at_index(w, key - '0'); 299 if (wp != NULL && window_pane_visible(wp)) 300 window_set_active_pane(w, wp); 301 server_clear_identify(c); 302 return; 303 } 304 305 /* Handle status line. */ 306 if (!(c->flags & CLIENT_READONLY)) { 307 status_message_clear(c); 308 server_clear_identify(c); 309 } 310 if (c->prompt_string != NULL) { 311 if (!(c->flags & CLIENT_READONLY)) 312 status_prompt_key(c, key); 313 return; 314 } 315 316 /* Check for mouse keys. */ 317 if (key == KEYC_MOUSE) { 318 if (c->flags & CLIENT_READONLY) 319 return; 320 if (options_get_number(oo, "mouse-select-pane") && 321 ((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) || 322 wp->mode != &window_copy_mode)) { 323 /* 324 * Allow pane switching in copy mode only by mouse down 325 * (click). 326 */ 327 window_set_active_at(w, mouse->x, mouse->y); 328 server_redraw_window_borders(w); 329 wp = w->active; 330 } 331 if (mouse->y + 1 == c->tty.sy && 332 options_get_number(oo, "mouse-select-window") && 333 options_get_number(oo, "status")) { 334 if (mouse->b == MOUSE_UP && 335 c->last_mouse.b != MOUSE_UP) { 336 status_set_window_at(c, mouse->x); 337 return; 338 } 339 if (mouse->b & MOUSE_45) { 340 if ((mouse->b & MOUSE_BUTTON) == MOUSE_1) { 341 session_previous(c->session, 0); 342 server_redraw_session(s); 343 } 344 if ((mouse->b & MOUSE_BUTTON) == MOUSE_2) { 345 session_next(c->session, 0); 346 server_redraw_session(s); 347 } 348 return; 349 } 350 } 351 if (options_get_number(oo, "mouse-resize-pane")) 352 layout_resize_pane_mouse(c, mouse); 353 memcpy(&c->last_mouse, mouse, sizeof c->last_mouse); 354 window_pane_mouse(wp, c->session, mouse); 355 return; 356 } 357 358 /* Is this a prefix key? */ 359 keylist = options_get_data(&c->session->options, "prefix"); 360 isprefix = 0; 361 for (i = 0; i < ARRAY_LENGTH(keylist); i++) { 362 if (key == ARRAY_ITEM(keylist, i)) { 363 isprefix = 1; 364 break; 365 } 366 } 367 368 /* No previous prefix key. */ 369 if (!(c->flags & CLIENT_PREFIX)) { 370 if (isprefix) 371 c->flags |= CLIENT_PREFIX; 372 else { 373 /* Try as a non-prefix key binding. */ 374 if ((bd = key_bindings_lookup(key)) == NULL) { 375 if (!(c->flags & CLIENT_READONLY)) 376 window_pane_key(wp, c->session, key); 377 } else 378 key_bindings_dispatch(bd, c); 379 } 380 return; 381 } 382 383 /* Prefix key already pressed. Reset prefix and lookup key. */ 384 c->flags &= ~CLIENT_PREFIX; 385 if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { 386 /* If repeating, treat this as a key, else ignore. */ 387 if (c->flags & CLIENT_REPEAT) { 388 c->flags &= ~CLIENT_REPEAT; 389 if (isprefix) 390 c->flags |= CLIENT_PREFIX; 391 else if (!(c->flags & CLIENT_READONLY)) 392 window_pane_key(wp, c->session, key); 393 } 394 return; 395 } 396 397 /* If already repeating, but this key can't repeat, skip it. */ 398 if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { 399 c->flags &= ~CLIENT_REPEAT; 400 if (isprefix) 401 c->flags |= CLIENT_PREFIX; 402 else if (!(c->flags & CLIENT_READONLY)) 403 window_pane_key(wp, c->session, key); 404 return; 405 } 406 407 /* If this key can repeat, reset the repeat flags and timer. */ 408 xtimeout = options_get_number(&c->session->options, "repeat-time"); 409 if (xtimeout != 0 && bd->can_repeat) { 410 c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; 411 412 tv.tv_sec = xtimeout / 1000; 413 tv.tv_usec = (xtimeout % 1000) * 1000L; 414 evtimer_del(&c->repeat_timer); 415 evtimer_add(&c->repeat_timer, &tv); 416 } 417 418 /* Dispatch the command. */ 419 key_bindings_dispatch(bd, c); 420 } 421 422 /* Client functions that need to happen every loop. */ 423 void 424 server_client_loop(void) 425 { 426 struct client *c; 427 struct window *w; 428 struct window_pane *wp; 429 u_int i; 430 431 for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 432 c = ARRAY_ITEM(&clients, i); 433 if (c == NULL) 434 continue; 435 436 server_client_check_exit(c); 437 if (c->session != NULL) { 438 server_client_check_redraw(c); 439 server_client_reset_state(c); 440 } 441 } 442 443 /* 444 * Any windows will have been redrawn as part of clients, so clear 445 * their flags now. 446 */ 447 for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 448 w = ARRAY_ITEM(&windows, i); 449 if (w == NULL) 450 continue; 451 452 w->flags &= ~WINDOW_REDRAW; 453 TAILQ_FOREACH(wp, &w->panes, entry) 454 wp->flags &= ~PANE_REDRAW; 455 } 456 } 457 458 /* 459 * Update cursor position and mode settings. The scroll region and attributes 460 * are cleared when idle (waiting for an event) as this is the most likely time 461 * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a 462 * compromise between excessive resets and likelihood of an interrupt. 463 * 464 * tty_region/tty_reset/tty_update_mode already take care of not resetting 465 * things that are already in their default state. 466 */ 467 void 468 server_client_reset_state(struct client *c) 469 { 470 struct window *w = c->session->curw->window; 471 struct window_pane *wp = w->active; 472 struct screen *s = wp->screen; 473 struct options *oo = &c->session->options; 474 struct options *wo = &w->options; 475 int status, mode; 476 477 if (c->flags & CLIENT_SUSPENDED) 478 return; 479 480 tty_region(&c->tty, 0, c->tty.sy - 1); 481 482 status = options_get_number(oo, "status"); 483 if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) 484 tty_cursor(&c->tty, 0, 0); 485 else 486 tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); 487 488 /* 489 * Resizing panes with the mouse requires at least button mode to give 490 * a smooth appearance. 491 */ 492 mode = s->mode; 493 if ((c->last_mouse.b & MOUSE_RESIZE_PANE) && 494 !(mode & (MODE_MOUSE_BUTTON|MODE_MOUSE_ANY))) 495 mode |= MODE_MOUSE_BUTTON; 496 497 /* 498 * Any mode will do for mouse-select-pane, but set standard mode if 499 * none. 500 */ 501 if ((mode & ALL_MOUSE_MODES) == 0) { 502 if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && 503 options_get_number(oo, "mouse-select-pane")) 504 mode |= MODE_MOUSE_STANDARD; 505 else if (options_get_number(oo, "mouse-resize-pane")) 506 mode |= MODE_MOUSE_STANDARD; 507 else if (options_get_number(oo, "mouse-select-window")) 508 mode |= MODE_MOUSE_STANDARD; 509 else if (options_get_number(wo, "mode-mouse")) 510 mode |= MODE_MOUSE_STANDARD; 511 } 512 513 /* 514 * Set UTF-8 mouse input if required. If the terminal is UTF-8, the 515 * user has set mouse-utf8 and any mouse mode is in effect, turn on 516 * UTF-8 mouse input. If the receiving terminal hasn't requested it 517 * (that is, it isn't in s->mode), then it'll be converted in 518 * input_mouse. 519 */ 520 if ((c->tty.flags & TTY_UTF8) && 521 (mode & ALL_MOUSE_MODES) && options_get_number(oo, "mouse-utf8")) 522 mode |= MODE_MOUSE_UTF8; 523 else 524 mode &= ~MODE_MOUSE_UTF8; 525 526 /* Set the terminal mode and reset attributes. */ 527 tty_update_mode(&c->tty, mode, s); 528 tty_reset(&c->tty); 529 } 530 531 /* Repeat time callback. */ 532 /* ARGSUSED */ 533 void 534 server_client_repeat_timer(unused int fd, unused short events, void *data) 535 { 536 struct client *c = data; 537 538 if (c->flags & CLIENT_REPEAT) 539 c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); 540 } 541 542 /* Check if client should be exited. */ 543 void 544 server_client_check_exit(struct client *c) 545 { 546 struct msg_exit_data exitdata; 547 548 if (!(c->flags & CLIENT_EXIT)) 549 return; 550 551 if (c->stdout_fd != -1 && c->stdout_event != NULL && 552 EVBUFFER_LENGTH(c->stdout_event->output) != 0) 553 return; 554 if (c->stderr_fd != -1 && c->stderr_event != NULL && 555 EVBUFFER_LENGTH(c->stderr_event->output) != 0) 556 return; 557 558 exitdata.retcode = c->retcode; 559 server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); 560 561 c->flags &= ~CLIENT_EXIT; 562 } 563 564 /* 565 * Check if the client should backoff. During backoff, data from external 566 * programs is not written to the terminal. When the existing data drains, the 567 * client is redrawn. 568 * 569 * There are two backoff phases - both the tty and client have backoff flags - 570 * the first to allow existing data to drain and the latter to ensure backoff 571 * is disabled until the redraw has finished and prevent the redraw triggering 572 * another backoff. 573 */ 574 void 575 server_client_check_backoff(struct client *c) 576 { 577 struct tty *tty = &c->tty; 578 size_t used; 579 580 used = EVBUFFER_LENGTH(tty->event->output); 581 582 /* 583 * If in the second backoff phase (redrawing), don't check backoff 584 * until the redraw has completed (or enough of it to drop below the 585 * backoff threshold). 586 */ 587 if (c->flags & CLIENT_BACKOFF) { 588 if (used > BACKOFF_THRESHOLD) 589 return; 590 c->flags &= ~CLIENT_BACKOFF; 591 return; 592 } 593 594 /* Once drained, allow data through again and schedule redraw. */ 595 if (tty->flags & TTY_BACKOFF) { 596 if (used != 0) 597 return; 598 tty->flags &= ~TTY_BACKOFF; 599 c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS); 600 return; 601 } 602 603 /* If too much data, start backoff. */ 604 if (used > BACKOFF_THRESHOLD) 605 tty->flags |= TTY_BACKOFF; 606 } 607 608 /* Check for client redraws. */ 609 void 610 server_client_check_redraw(struct client *c) 611 { 612 struct session *s = c->session; 613 struct window_pane *wp; 614 int flags, redraw; 615 616 flags = c->tty.flags & TTY_FREEZE; 617 c->tty.flags &= ~TTY_FREEZE; 618 619 if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { 620 if (options_get_number(&s->options, "set-titles")) 621 server_client_set_title(c); 622 623 if (c->message_string != NULL) 624 redraw = status_message_redraw(c); 625 else if (c->prompt_string != NULL) 626 redraw = status_prompt_redraw(c); 627 else 628 redraw = status_redraw(c); 629 if (!redraw) 630 c->flags &= ~CLIENT_STATUS; 631 } 632 633 if (c->flags & CLIENT_REDRAW) { 634 screen_redraw_screen(c, 0, 0); 635 c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS); 636 } else if (c->flags & CLIENT_REDRAWWINDOW) { 637 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) 638 screen_redraw_pane(c, wp); 639 c->flags &= ~CLIENT_REDRAWWINDOW; 640 } else { 641 TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { 642 if (wp->flags & PANE_REDRAW) 643 screen_redraw_pane(c, wp); 644 } 645 } 646 647 if (c->flags & CLIENT_BORDERS) 648 screen_redraw_screen(c, 0, 1); 649 650 if (c->flags & CLIENT_STATUS) 651 screen_redraw_screen(c, 1, 0); 652 653 c->tty.flags |= flags; 654 655 c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS); 656 } 657 658 /* Set client title. */ 659 void 660 server_client_set_title(struct client *c) 661 { 662 struct session *s = c->session; 663 const char *template; 664 char *title; 665 666 template = options_get_string(&s->options, "set-titles-string"); 667 668 title = status_replace(c, NULL, NULL, NULL, template, time(NULL), 1); 669 if (c->title == NULL || strcmp(title, c->title) != 0) { 670 if (c->title != NULL) 671 xfree(c->title); 672 c->title = xstrdup(title); 673 tty_set_title(&c->tty, c->title); 674 } 675 xfree(title); 676 } 677 678 /* 679 * Error callback for client stdin. Caller must increase reference count when 680 * enabling event! 681 */ 682 void 683 server_client_in_callback( 684 unused struct bufferevent *bufev, unused short what, void *data) 685 { 686 struct client *c = data; 687 688 c->references--; 689 if (c->flags & CLIENT_DEAD) 690 return; 691 692 bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE); 693 setblocking(c->stdin_fd, 1); 694 close(c->stdin_fd); 695 c->stdin_fd = -1; 696 697 if (c->stdin_callback != NULL) 698 c->stdin_callback(c, c->stdin_data); 699 } 700 701 /* Error callback for client stdout. */ 702 void 703 server_client_out_callback( 704 unused struct bufferevent *bufev, unused short what, unused void *data) 705 { 706 struct client *c = data; 707 708 bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE); 709 setblocking(c->stdout_fd, 1); 710 close(c->stdout_fd); 711 c->stdout_fd = -1; 712 } 713 714 /* Error callback for client stderr. */ 715 void 716 server_client_err_callback( 717 unused struct bufferevent *bufev, unused short what, unused void *data) 718 { 719 struct client *c = data; 720 721 bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE); 722 setblocking(c->stderr_fd, 1); 723 close(c->stderr_fd); 724 c->stderr_fd = -1; 725 } 726 727 /* Dispatch message from client. */ 728 int 729 server_client_msg_dispatch(struct client *c) 730 { 731 struct imsg imsg; 732 struct msg_command_data commanddata; 733 struct msg_identify_data identifydata; 734 struct msg_environ_data environdata; 735 ssize_t n, datalen; 736 737 if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) 738 return (-1); 739 740 for (;;) { 741 if ((n = imsg_get(&c->ibuf, &imsg)) == -1) 742 return (-1); 743 if (n == 0) 744 return (0); 745 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 746 747 if (imsg.hdr.peerid != PROTOCOL_VERSION) { 748 server_write_client(c, MSG_VERSION, NULL, 0); 749 c->flags |= CLIENT_BAD; 750 imsg_free(&imsg); 751 continue; 752 } 753 754 log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd); 755 switch (imsg.hdr.type) { 756 case MSG_COMMAND: 757 if (datalen != sizeof commanddata) 758 fatalx("bad MSG_COMMAND size"); 759 memcpy(&commanddata, imsg.data, sizeof commanddata); 760 761 server_client_msg_command(c, &commanddata); 762 break; 763 case MSG_IDENTIFY: 764 if (datalen != sizeof identifydata) 765 fatalx("bad MSG_IDENTIFY size"); 766 if (imsg.fd == -1) 767 fatalx("MSG_IDENTIFY missing fd"); 768 memcpy(&identifydata, imsg.data, sizeof identifydata); 769 770 c->stdin_fd = imsg.fd; 771 c->stdin_event = bufferevent_new(c->stdin_fd, 772 NULL, NULL, server_client_in_callback, c); 773 if (c->stdin_event == NULL) 774 fatalx("failed to create stdin event"); 775 setblocking(c->stdin_fd, 0); 776 777 server_client_msg_identify(c, &identifydata, imsg.fd); 778 break; 779 case MSG_STDOUT: 780 if (datalen != 0) 781 fatalx("bad MSG_STDOUT size"); 782 if (imsg.fd == -1) 783 fatalx("MSG_STDOUT missing fd"); 784 785 c->stdout_fd = imsg.fd; 786 c->stdout_event = bufferevent_new(c->stdout_fd, 787 NULL, NULL, server_client_out_callback, c); 788 if (c->stdout_event == NULL) 789 fatalx("failed to create stdout event"); 790 setblocking(c->stdout_fd, 0); 791 792 break; 793 case MSG_STDERR: 794 if (datalen != 0) 795 fatalx("bad MSG_STDERR size"); 796 if (imsg.fd == -1) 797 fatalx("MSG_STDERR missing fd"); 798 799 c->stderr_fd = imsg.fd; 800 c->stderr_event = bufferevent_new(c->stderr_fd, 801 NULL, NULL, server_client_err_callback, c); 802 if (c->stderr_event == NULL) 803 fatalx("failed to create stderr event"); 804 setblocking(c->stderr_fd, 0); 805 806 break; 807 case MSG_RESIZE: 808 if (datalen != 0) 809 fatalx("bad MSG_RESIZE size"); 810 811 if (tty_resize(&c->tty)) { 812 recalculate_sizes(); 813 server_redraw_client(c); 814 } 815 break; 816 case MSG_EXITING: 817 if (datalen != 0) 818 fatalx("bad MSG_EXITING size"); 819 820 c->session = NULL; 821 tty_close(&c->tty); 822 server_write_client(c, MSG_EXITED, NULL, 0); 823 break; 824 case MSG_WAKEUP: 825 case MSG_UNLOCK: 826 if (datalen != 0) 827 fatalx("bad MSG_WAKEUP size"); 828 829 if (!(c->flags & CLIENT_SUSPENDED)) 830 break; 831 c->flags &= ~CLIENT_SUSPENDED; 832 833 if (gettimeofday(&c->activity_time, NULL) != 0) 834 fatal("gettimeofday"); 835 if (c->session != NULL) 836 session_update_activity(c->session); 837 838 tty_start_tty(&c->tty); 839 server_redraw_client(c); 840 recalculate_sizes(); 841 break; 842 case MSG_ENVIRON: 843 if (datalen != sizeof environdata) 844 fatalx("bad MSG_ENVIRON size"); 845 memcpy(&environdata, imsg.data, sizeof environdata); 846 847 environdata.var[(sizeof environdata.var) - 1] = '\0'; 848 if (strchr(environdata.var, '=') != NULL) 849 environ_put(&c->environ, environdata.var); 850 break; 851 case MSG_SHELL: 852 if (datalen != 0) 853 fatalx("bad MSG_SHELL size"); 854 855 server_client_msg_shell(c); 856 break; 857 default: 858 fatalx("unexpected message"); 859 } 860 861 imsg_free(&imsg); 862 } 863 } 864 865 /* Callback to send error message to client. */ 866 void printflike2 867 server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...) 868 { 869 va_list ap; 870 871 va_start(ap, fmt); 872 evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap); 873 va_end(ap); 874 875 bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1); 876 ctx->cmdclient->retcode = 1; 877 } 878 879 /* Callback to send print message to client. */ 880 void printflike2 881 server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...) 882 { 883 va_list ap; 884 885 va_start(ap, fmt); 886 evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); 887 va_end(ap); 888 889 bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); 890 } 891 892 /* Callback to send print message to client, if not quiet. */ 893 void printflike2 894 server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...) 895 { 896 va_list ap; 897 898 if (options_get_number(&global_options, "quiet")) 899 return; 900 901 va_start(ap, fmt); 902 evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); 903 va_end(ap); 904 905 bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); 906 } 907 908 /* Handle command message. */ 909 void 910 server_client_msg_command(struct client *c, struct msg_command_data *data) 911 { 912 struct cmd_ctx ctx; 913 struct cmd_list *cmdlist = NULL; 914 int argc; 915 char **argv, *cause; 916 917 ctx.error = server_client_msg_error; 918 ctx.print = server_client_msg_print; 919 ctx.info = server_client_msg_info; 920 921 ctx.msgdata = data; 922 ctx.curclient = NULL; 923 924 ctx.cmdclient = c; 925 926 argc = data->argc; 927 data->argv[(sizeof data->argv) - 1] = '\0'; 928 if (cmd_unpack_argv(data->argv, sizeof data->argv, argc, &argv) != 0) { 929 server_client_msg_error(&ctx, "command too long"); 930 goto error; 931 } 932 933 if (argc == 0) { 934 argc = 1; 935 argv = xcalloc(1, sizeof *argv); 936 *argv = xstrdup("new-session"); 937 } 938 939 if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) { 940 server_client_msg_error(&ctx, "%s", cause); 941 cmd_free_argv(argc, argv); 942 goto error; 943 } 944 cmd_free_argv(argc, argv); 945 946 if (cmd_list_exec(cmdlist, &ctx) != 1) 947 c->flags |= CLIENT_EXIT; 948 cmd_list_free(cmdlist); 949 return; 950 951 error: 952 if (cmdlist != NULL) 953 cmd_list_free(cmdlist); 954 c->flags |= CLIENT_EXIT; 955 } 956 957 /* Handle identify message. */ 958 void 959 server_client_msg_identify( 960 struct client *c, struct msg_identify_data *data, int fd) 961 { 962 int tty_fd; 963 964 c->cwd = NULL; 965 data->cwd[(sizeof data->cwd) - 1] = '\0'; 966 if (*data->cwd != '\0') 967 c->cwd = xstrdup(data->cwd); 968 969 if (!isatty(fd)) 970 return; 971 if ((tty_fd = dup(fd)) == -1) 972 fatal("dup failed"); 973 data->term[(sizeof data->term) - 1] = '\0'; 974 tty_init(&c->tty, tty_fd, data->term); 975 if (data->flags & IDENTIFY_UTF8) 976 c->tty.flags |= TTY_UTF8; 977 if (data->flags & IDENTIFY_256COLOURS) 978 c->tty.term_flags |= TERM_256COLOURS; 979 else if (data->flags & IDENTIFY_88COLOURS) 980 c->tty.term_flags |= TERM_88COLOURS; 981 c->tty.key_callback = server_client_handle_key; 982 c->tty.key_data = c; 983 984 tty_resize(&c->tty); 985 986 c->flags |= CLIENT_TERMINAL; 987 } 988 989 /* Handle shell message. */ 990 void 991 server_client_msg_shell(struct client *c) 992 { 993 struct msg_shell_data data; 994 const char *shell; 995 996 shell = options_get_string(&global_s_options, "default-shell"); 997 998 if (*shell == '\0' || areshell(shell)) 999 shell = _PATH_BSHELL; 1000 if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) 1001 strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); 1002 1003 server_write_client(c, MSG_SHELL, &data, sizeof data); 1004 c->flags |= CLIENT_BAD; /* it will die after exec */ 1005 } 1006