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