server-client.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <sys/ioctl.h>
  19. #include <sys/uio.h>
  20. #include <errno.h>
  21. #include <event.h>
  22. #include <fcntl.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <unistd.h>
  27. #include "tmux.h"
  28. #include "tmate.h"
  29. void server_client_free(int, short, void *);
  30. void server_client_check_focus(struct window_pane *);
  31. void server_client_check_resize(struct window_pane *);
  32. key_code server_client_check_mouse(struct client *);
  33. void server_client_repeat_timer(int, short, void *);
  34. void server_client_check_exit(struct client *);
  35. void server_client_check_redraw(struct client *);
  36. void server_client_set_title(struct client *);
  37. void server_client_reset_state(struct client *);
  38. int server_client_assume_paste(struct session *);
  39. void server_client_dispatch(struct imsg *, void *);
  40. void server_client_dispatch_command(struct client *, struct imsg *);
  41. void server_client_dispatch_identify(struct client *, struct imsg *);
  42. void server_client_dispatch_shell(struct client *);
  43. /* Check if this client is inside this server. */
  44. int
  45. server_client_check_nested(struct client *c)
  46. {
  47. struct environ_entry *envent;
  48. struct window_pane *wp;
  49. if (c->tty.path == NULL)
  50. return (0);
  51. envent = environ_find(c->environ, "TMUX");
  52. if (envent == NULL || *envent->value == '\0')
  53. return (0);
  54. RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
  55. if (strcmp(wp->tty, c->tty.path) == 0)
  56. return (1);
  57. }
  58. return (0);
  59. }
  60. /* Set client key table. */
  61. void
  62. server_client_set_key_table(struct client *c, const char *name)
  63. {
  64. if (name == NULL)
  65. name = server_client_get_key_table(c);
  66. key_bindings_unref_table(c->keytable);
  67. c->keytable = key_bindings_get_table(name, 1);
  68. c->keytable->references++;
  69. }
  70. /* Get default key table. */
  71. const char *
  72. server_client_get_key_table(struct client *c)
  73. {
  74. struct session *s = c->session;
  75. const char *name;
  76. if (s == NULL)
  77. return ("root");
  78. name = options_get_string(s->options, "key-table");
  79. if (*name == '\0')
  80. return ("root");
  81. return (name);
  82. }
  83. /* Create a new client. */
  84. void
  85. server_client_create(int fd)
  86. {
  87. struct client *c;
  88. setblocking(fd, 0);
  89. c = xcalloc(1, sizeof *c);
  90. c->references = 1;
  91. c->peer = proc_add_peer(server_proc, fd, server_client_dispatch, c);
  92. if (gettimeofday(&c->creation_time, NULL) != 0)
  93. fatal("gettimeofday failed");
  94. memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
  95. c->environ = environ_create();
  96. c->fd = -1;
  97. c->cwd = NULL;
  98. c->cmdq = cmdq_new(c);
  99. c->cmdq->client_exit = 1;
  100. c->stdin_data = evbuffer_new();
  101. c->stdout_data = evbuffer_new();
  102. c->stderr_data = evbuffer_new();
  103. c->tty.fd = -1;
  104. c->title = NULL;
  105. c->session = NULL;
  106. c->last_session = NULL;
  107. c->tty.sx = 80;
  108. c->tty.sy = 24;
  109. screen_init(&c->status, c->tty.sx, 1, 0);
  110. c->message_string = NULL;
  111. TAILQ_INIT(&c->message_log);
  112. c->prompt_string = NULL;
  113. c->prompt_buffer = NULL;
  114. c->prompt_index = 0;
  115. c->flags |= CLIENT_FOCUSED;
  116. c->keytable = key_bindings_get_table("root", 1);
  117. c->keytable->references++;
  118. evtimer_set(&c->repeat_timer, server_client_repeat_timer, c);
  119. TAILQ_INSERT_TAIL(&clients, c, entry);
  120. log_debug("new client %p", c);
  121. }
  122. /* Open client terminal if needed. */
  123. int
  124. server_client_open(struct client *c, char **cause)
  125. {
  126. if (c->flags & CLIENT_CONTROL)
  127. return (0);
  128. if (strcmp(c->ttyname, "/dev/tty") == 0) {
  129. *cause = xstrdup("can't use /dev/tty");
  130. return (-1);
  131. }
  132. if (!(c->flags & CLIENT_TERMINAL)) {
  133. *cause = xstrdup("not a terminal");
  134. return (-1);
  135. }
  136. if (tty_open(&c->tty, cause) != 0)
  137. return (-1);
  138. return (0);
  139. }
  140. /* Lost a client. */
  141. void
  142. server_client_lost(struct client *c)
  143. {
  144. struct message_entry *msg, *msg1;
  145. c->flags |= CLIENT_DEAD;
  146. status_prompt_clear(c);
  147. status_message_clear(c);
  148. if (c->stdin_callback != NULL)
  149. c->stdin_callback(c, 1, c->stdin_callback_data);
  150. TAILQ_REMOVE(&clients, c, entry);
  151. log_debug("lost client %p", c);
  152. /*
  153. * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called
  154. * and tty_free might close an unrelated fd.
  155. */
  156. if (c->flags & CLIENT_TERMINAL)
  157. tty_free(&c->tty);
  158. free(c->ttyname);
  159. free(c->term);
  160. evbuffer_free(c->stdin_data);
  161. evbuffer_free(c->stdout_data);
  162. if (c->stderr_data != c->stdout_data)
  163. evbuffer_free(c->stderr_data);
  164. if (event_initialized(&c->status_timer))
  165. evtimer_del(&c->status_timer);
  166. screen_free(&c->status);
  167. free(c->title);
  168. free((void *)c->cwd);
  169. evtimer_del(&c->repeat_timer);
  170. key_bindings_unref_table(c->keytable);
  171. if (event_initialized(&c->identify_timer))
  172. evtimer_del(&c->identify_timer);
  173. free(c->message_string);
  174. if (event_initialized(&c->message_timer))
  175. evtimer_del(&c->message_timer);
  176. TAILQ_FOREACH_SAFE(msg, &c->message_log, entry, msg1) {
  177. free(msg->msg);
  178. TAILQ_REMOVE(&c->message_log, msg, entry);
  179. free(msg);
  180. }
  181. free(c->prompt_string);
  182. free(c->prompt_buffer);
  183. c->cmdq->flags |= CMD_Q_DEAD;
  184. cmdq_free(c->cmdq);
  185. c->cmdq = NULL;
  186. environ_free(c->environ);
  187. proc_remove_peer(c->peer);
  188. c->peer = NULL;
  189. server_client_unref(c);
  190. server_add_accept(0); /* may be more file descriptors now */
  191. recalculate_sizes();
  192. server_check_unattached();
  193. server_update_socket();
  194. }
  195. /* Remove reference from a client. */
  196. void
  197. server_client_unref(struct client *c)
  198. {
  199. log_debug("unref client %p (%d references)", c, c->references);
  200. c->references--;
  201. if (c->references == 0)
  202. event_once(-1, EV_TIMEOUT, server_client_free, c, NULL);
  203. }
  204. /* Free dead client. */
  205. void
  206. server_client_free(__unused int fd, __unused short events, void *arg)
  207. {
  208. struct client *c = arg;
  209. log_debug("free client %p (%d references)", c, c->references);
  210. if (c->references == 0)
  211. free(c);
  212. }
  213. /* Detach a client. */
  214. void
  215. server_client_detach(struct client *c, enum msgtype msgtype)
  216. {
  217. struct session *s = c->session;
  218. if (s == NULL)
  219. return;
  220. hooks_run(c->session->hooks, c, NULL, "client-detached");
  221. proc_send_s(c->peer, msgtype, s->name);
  222. }
  223. /* Check for mouse keys. */
  224. key_code
  225. server_client_check_mouse(struct client *c)
  226. {
  227. struct session *s = c->session;
  228. struct mouse_event *m = &c->tty.mouse;
  229. struct window *w;
  230. struct window_pane *wp;
  231. enum { NOTYPE, DOWN, UP, DRAG, WHEEL } type = NOTYPE;
  232. enum { NOWHERE, PANE, STATUS, BORDER } where = NOWHERE;
  233. u_int x, y, b;
  234. key_code key;
  235. log_debug("mouse %02x at %u,%u (last %u,%u) (%d)", m->b, m->x, m->y,
  236. m->lx, m->ly, c->tty.mouse_drag_flag);
  237. /* What type of event is this? */
  238. if (MOUSE_DRAG(m->b)) {
  239. type = DRAG;
  240. if (c->tty.mouse_drag_flag) {
  241. x = m->x, y = m->y, b = m->b;
  242. log_debug("drag update at %u,%u", x, y);
  243. } else {
  244. x = m->lx, y = m->ly, b = m->lb;
  245. log_debug("drag start at %u,%u", x, y);
  246. }
  247. } else if (MOUSE_WHEEL(m->b)) {
  248. type = WHEEL;
  249. x = m->x, y = m->y, b = m->b;
  250. log_debug("wheel at %u,%u", x, y);
  251. } else if (MOUSE_BUTTONS(m->b) == 3) {
  252. type = UP;
  253. x = m->x, y = m->y, b = m->lb;
  254. log_debug("up at %u,%u", x, y);
  255. } else {
  256. type = DOWN;
  257. x = m->x, y = m->y, b = m->b;
  258. log_debug("down at %u,%u", x, y);
  259. }
  260. if (type == NOTYPE)
  261. return (KEYC_UNKNOWN);
  262. /* Always save the session. */
  263. m->s = s->id;
  264. /* Is this on the status line? */
  265. m->statusat = status_at_line(c);
  266. if (m->statusat != -1 && y == (u_int)m->statusat) {
  267. w = status_get_window_at(c, x);
  268. if (w == NULL)
  269. return (KEYC_UNKNOWN);
  270. m->w = w->id;
  271. where = STATUS;
  272. } else
  273. m->w = -1;
  274. /* Not on status line. Adjust position and check for border or pane. */
  275. if (where == NOWHERE) {
  276. if (m->statusat == 0 && y > 0)
  277. y--;
  278. else if (m->statusat > 0 && y >= (u_int)m->statusat)
  279. y = m->statusat - 1;
  280. TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
  281. if ((wp->xoff + wp->sx == x &&
  282. wp->yoff <= 1 + y &&
  283. wp->yoff + wp->sy >= y) ||
  284. (wp->yoff + wp->sy == y &&
  285. wp->xoff <= 1 + x &&
  286. wp->xoff + wp->sx >= x))
  287. break;
  288. }
  289. if (wp != NULL)
  290. where = BORDER;
  291. else {
  292. wp = window_get_active_at(s->curw->window, x, y);
  293. if (wp != NULL) {
  294. where = PANE;
  295. log_debug("mouse at %u,%u is on pane %%%u",
  296. x, y, wp->id);
  297. }
  298. }
  299. if (where == NOWHERE)
  300. return (KEYC_UNKNOWN);
  301. m->wp = wp->id;
  302. m->w = wp->window->id;
  303. } else
  304. m->wp = -1;
  305. /* Stop dragging if needed. */
  306. if (type != DRAG && c->tty.mouse_drag_flag) {
  307. if (c->tty.mouse_drag_release != NULL)
  308. c->tty.mouse_drag_release(c, m);
  309. c->tty.mouse_drag_update = NULL;
  310. c->tty.mouse_drag_release = NULL;
  311. /*
  312. * End a mouse drag by passing a MouseDragEnd key corresponding
  313. * to the button that started the drag.
  314. */
  315. switch (c->tty.mouse_drag_flag) {
  316. case 1:
  317. if (where == PANE)
  318. key = KEYC_MOUSEDRAGEND1_PANE;
  319. if (where == STATUS)
  320. key = KEYC_MOUSEDRAGEND1_STATUS;
  321. if (where == BORDER)
  322. key = KEYC_MOUSEDRAGEND1_BORDER;
  323. break;
  324. case 2:
  325. if (where == PANE)
  326. key = KEYC_MOUSEDRAGEND2_PANE;
  327. if (where == STATUS)
  328. key = KEYC_MOUSEDRAGEND2_STATUS;
  329. if (where == BORDER)
  330. key = KEYC_MOUSEDRAGEND2_BORDER;
  331. break;
  332. case 3:
  333. if (where == PANE)
  334. key = KEYC_MOUSEDRAGEND3_PANE;
  335. if (where == STATUS)
  336. key = KEYC_MOUSEDRAGEND3_STATUS;
  337. if (where == BORDER)
  338. key = KEYC_MOUSEDRAGEND3_BORDER;
  339. break;
  340. default:
  341. key = KEYC_MOUSE;
  342. break;
  343. }
  344. c->tty.mouse_drag_flag = 0;
  345. return (key);
  346. }
  347. /* Convert to a key binding. */
  348. key = KEYC_UNKNOWN;
  349. switch (type) {
  350. case NOTYPE:
  351. break;
  352. case DRAG:
  353. if (c->tty.mouse_drag_update != NULL)
  354. c->tty.mouse_drag_update(c, m);
  355. else {
  356. switch (MOUSE_BUTTONS(b)) {
  357. case 0:
  358. if (where == PANE)
  359. key = KEYC_MOUSEDRAG1_PANE;
  360. if (where == STATUS)
  361. key = KEYC_MOUSEDRAG1_STATUS;
  362. if (where == BORDER)
  363. key = KEYC_MOUSEDRAG1_BORDER;
  364. break;
  365. case 1:
  366. if (where == PANE)
  367. key = KEYC_MOUSEDRAG2_PANE;
  368. if (where == STATUS)
  369. key = KEYC_MOUSEDRAG2_STATUS;
  370. if (where == BORDER)
  371. key = KEYC_MOUSEDRAG2_BORDER;
  372. break;
  373. case 2:
  374. if (where == PANE)
  375. key = KEYC_MOUSEDRAG3_PANE;
  376. if (where == STATUS)
  377. key = KEYC_MOUSEDRAG3_STATUS;
  378. if (where == BORDER)
  379. key = KEYC_MOUSEDRAG3_BORDER;
  380. break;
  381. }
  382. }
  383. /*
  384. * Begin a drag by setting the flag to a non-zero value that
  385. * corresponds to the mouse button in use.
  386. */
  387. c->tty.mouse_drag_flag = MOUSE_BUTTONS(b) + 1;
  388. break;
  389. case WHEEL:
  390. if (MOUSE_BUTTONS(b) == MOUSE_WHEEL_UP) {
  391. if (where == PANE)
  392. key = KEYC_WHEELUP_PANE;
  393. if (where == STATUS)
  394. key = KEYC_WHEELUP_STATUS;
  395. if (where == BORDER)
  396. key = KEYC_WHEELUP_BORDER;
  397. } else {
  398. if (where == PANE)
  399. key = KEYC_WHEELDOWN_PANE;
  400. if (where == STATUS)
  401. key = KEYC_WHEELDOWN_STATUS;
  402. if (where == BORDER)
  403. key = KEYC_WHEELDOWN_BORDER;
  404. }
  405. break;
  406. case UP:
  407. switch (MOUSE_BUTTONS(b)) {
  408. case 0:
  409. if (where == PANE)
  410. key = KEYC_MOUSEUP1_PANE;
  411. if (where == STATUS)
  412. key = KEYC_MOUSEUP1_STATUS;
  413. if (where == BORDER)
  414. key = KEYC_MOUSEUP1_BORDER;
  415. break;
  416. case 1:
  417. if (where == PANE)
  418. key = KEYC_MOUSEUP2_PANE;
  419. if (where == STATUS)
  420. key = KEYC_MOUSEUP2_STATUS;
  421. if (where == BORDER)
  422. key = KEYC_MOUSEUP2_BORDER;
  423. break;
  424. case 2:
  425. if (where == PANE)
  426. key = KEYC_MOUSEUP3_PANE;
  427. if (where == STATUS)
  428. key = KEYC_MOUSEUP3_STATUS;
  429. if (where == BORDER)
  430. key = KEYC_MOUSEUP3_BORDER;
  431. break;
  432. }
  433. break;
  434. case DOWN:
  435. switch (MOUSE_BUTTONS(b)) {
  436. case 0:
  437. if (where == PANE)
  438. key = KEYC_MOUSEDOWN1_PANE;
  439. if (where == STATUS)
  440. key = KEYC_MOUSEDOWN1_STATUS;
  441. if (where == BORDER)
  442. key = KEYC_MOUSEDOWN1_BORDER;
  443. break;
  444. case 1:
  445. if (where == PANE)
  446. key = KEYC_MOUSEDOWN2_PANE;
  447. if (where == STATUS)
  448. key = KEYC_MOUSEDOWN2_STATUS;
  449. if (where == BORDER)
  450. key = KEYC_MOUSEDOWN2_BORDER;
  451. break;
  452. case 2:
  453. if (where == PANE)
  454. key = KEYC_MOUSEDOWN3_PANE;
  455. if (where == STATUS)
  456. key = KEYC_MOUSEDOWN3_STATUS;
  457. if (where == BORDER)
  458. key = KEYC_MOUSEDOWN3_BORDER;
  459. break;
  460. }
  461. break;
  462. }
  463. if (key == KEYC_UNKNOWN)
  464. return (KEYC_UNKNOWN);
  465. /* Apply modifiers if any. */
  466. if (b & MOUSE_MASK_META)
  467. key |= KEYC_ESCAPE;
  468. if (b & MOUSE_MASK_CTRL)
  469. key |= KEYC_CTRL;
  470. if (b & MOUSE_MASK_SHIFT)
  471. key |= KEYC_SHIFT;
  472. return (key);
  473. }
  474. /* Is this fast enough to probably be a paste? */
  475. int
  476. server_client_assume_paste(struct session *s)
  477. {
  478. struct timeval tv;
  479. int t;
  480. if ((t = options_get_number(s->options, "assume-paste-time")) == 0)
  481. return (0);
  482. timersub(&s->activity_time, &s->last_activity_time, &tv);
  483. if (tv.tv_sec == 0 && tv.tv_usec < t * 1000) {
  484. log_debug("session %s pasting (flag %d)", s->name,
  485. !!(s->flags & SESSION_PASTING));
  486. if (s->flags & SESSION_PASTING)
  487. return (1);
  488. s->flags |= SESSION_PASTING;
  489. return (0);
  490. }
  491. log_debug("session %s not pasting", s->name);
  492. s->flags &= ~SESSION_PASTING;
  493. return (0);
  494. }
  495. /* Handle data key input from client. */
  496. void
  497. server_client_handle_key(struct client *c, key_code key)
  498. {
  499. struct mouse_event *m = &c->tty.mouse;
  500. struct session *s = c->session;
  501. struct window *w;
  502. struct window_pane *wp;
  503. struct timeval tv;
  504. struct key_table *table;
  505. struct key_binding bd_find, *bd;
  506. int xtimeout;
  507. /* Check the client is good to accept input. */
  508. if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
  509. return;
  510. w = s->curw->window;
  511. /* Update the activity timer. */
  512. if (gettimeofday(&c->activity_time, NULL) != 0)
  513. fatal("gettimeofday failed");
  514. session_update_activity(s, &c->activity_time);
  515. /* Number keys jump to pane in identify mode. */
  516. if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') {
  517. if (c->flags & CLIENT_READONLY)
  518. return;
  519. window_unzoom(w);
  520. wp = window_pane_at_index(w, key - '0');
  521. if (wp != NULL && window_pane_visible(wp))
  522. window_set_active_pane(w, wp);
  523. server_clear_identify(c);
  524. return;
  525. }
  526. /* Handle status line. */
  527. if (!(c->flags & CLIENT_READONLY)) {
  528. #ifdef TMATE
  529. if (!(c->flags & CLIENT_FORCE_STATUS))
  530. #endif
  531. status_message_clear(c);
  532. server_clear_identify(c);
  533. }
  534. if (c->prompt_string != NULL) {
  535. if (!(c->flags & CLIENT_READONLY))
  536. status_prompt_key(c, key);
  537. return;
  538. }
  539. /* Check for mouse keys. */
  540. if (key == KEYC_MOUSE) {
  541. if (c->flags & CLIENT_READONLY)
  542. return;
  543. key = server_client_check_mouse(c);
  544. if (key == KEYC_UNKNOWN)
  545. return;
  546. m->valid = 1;
  547. m->key = key;
  548. if (!options_get_number(s->options, "mouse"))
  549. goto forward;
  550. } else
  551. m->valid = 0;
  552. /* Treat everything as a regular key when pasting is detected. */
  553. if (!KEYC_IS_MOUSE(key) && server_client_assume_paste(s))
  554. goto forward;
  555. retry:
  556. /* Try to see if there is a key binding in the current table. */
  557. bd_find.key = key;
  558. bd = RB_FIND(key_bindings, &c->keytable->key_bindings, &bd_find);
  559. if (bd != NULL) {
  560. /*
  561. * Key was matched in this table. If currently repeating but a
  562. * non-repeating binding was found, stop repeating and try
  563. * again in the root table.
  564. */
  565. if ((c->flags & CLIENT_REPEAT) && !bd->can_repeat) {
  566. server_client_set_key_table(c, NULL);
  567. c->flags &= ~CLIENT_REPEAT;
  568. server_status_client(c);
  569. goto retry;
  570. }
  571. /*
  572. * Take a reference to this table to make sure the key binding
  573. * doesn't disappear.
  574. */
  575. table = c->keytable;
  576. table->references++;
  577. /*
  578. * If this is a repeating key, start the timer. Otherwise reset
  579. * the client back to the root table.
  580. */
  581. xtimeout = options_get_number(s->options, "repeat-time");
  582. if (xtimeout != 0 && bd->can_repeat) {
  583. c->flags |= CLIENT_REPEAT;
  584. tv.tv_sec = xtimeout / 1000;
  585. tv.tv_usec = (xtimeout % 1000) * 1000L;
  586. evtimer_del(&c->repeat_timer);
  587. evtimer_add(&c->repeat_timer, &tv);
  588. } else {
  589. c->flags &= ~CLIENT_REPEAT;
  590. server_client_set_key_table(c, NULL);
  591. }
  592. server_status_client(c);
  593. /* Dispatch the key binding. */
  594. key_bindings_dispatch(bd, c, m);
  595. key_bindings_unref_table(table);
  596. return;
  597. }
  598. /*
  599. * No match in this table. If repeating, switch the client back to the
  600. * root table and try again.
  601. */
  602. if (c->flags & CLIENT_REPEAT) {
  603. server_client_set_key_table(c, NULL);
  604. c->flags &= ~CLIENT_REPEAT;
  605. server_status_client(c);
  606. goto retry;
  607. }
  608. /* If no match and we're not in the root table, that's it. */
  609. if (strcmp(c->keytable->name, server_client_get_key_table(c)) != 0) {
  610. server_client_set_key_table(c, NULL);
  611. server_status_client(c);
  612. return;
  613. }
  614. /*
  615. * No match, but in the root table. Prefix switches to the prefix table
  616. * and everything else is passed through.
  617. */
  618. if (key == (key_code)options_get_number(s->options, "prefix") ||
  619. key == (key_code)options_get_number(s->options, "prefix2")) {
  620. server_client_set_key_table(c, "prefix");
  621. server_status_client(c);
  622. return;
  623. }
  624. forward:
  625. if (c->flags & CLIENT_READONLY)
  626. return;
  627. if (KEYC_IS_MOUSE(key))
  628. wp = cmd_mouse_pane(m, NULL, NULL);
  629. else
  630. wp = w->active;
  631. if (wp != NULL)
  632. window_pane_key(wp, c, s, key, m);
  633. }
  634. /* Client functions that need to happen every loop. */
  635. void
  636. server_client_loop(void)
  637. {
  638. struct client *c;
  639. struct window *w;
  640. struct window_pane *wp;
  641. #ifdef TMATE
  642. int tmate_should_sync_layout = 0;
  643. #endif
  644. TAILQ_FOREACH(c, &clients, entry) {
  645. server_client_check_exit(c);
  646. if (c->session != NULL) {
  647. server_client_check_redraw(c);
  648. server_client_reset_state(c);
  649. }
  650. }
  651. /*
  652. * Any windows will have been redrawn as part of clients, so clear
  653. * their flags now. Also check pane focus and resize.
  654. */
  655. RB_FOREACH(w, windows, &windows) {
  656. #ifdef TMATE
  657. if (w->flags & WINDOW_REDRAW)
  658. tmate_should_sync_layout = 1;
  659. if (w->tmate_last_sync_active_pane != w->active)
  660. tmate_should_sync_layout = 1;
  661. #endif
  662. w->flags &= ~WINDOW_REDRAW;
  663. TAILQ_FOREACH(wp, &w->panes, entry) {
  664. if (wp->fd != -1) {
  665. server_client_check_focus(wp);
  666. server_client_check_resize(wp);
  667. }
  668. wp->flags &= ~PANE_REDRAW;
  669. }
  670. check_window_name(w);
  671. }
  672. #ifdef TMATE
  673. if (tmate_should_sync_layout)
  674. tmate_sync_layout();
  675. #endif
  676. }
  677. /* Check if pane should be resized. */
  678. void
  679. server_client_check_resize(struct window_pane *wp)
  680. {
  681. struct winsize ws;
  682. if (!(wp->flags & PANE_RESIZE))
  683. return;
  684. memset(&ws, 0, sizeof ws);
  685. ws.ws_col = wp->sx;
  686. ws.ws_row = wp->sy;
  687. if (ioctl(wp->fd, TIOCSWINSZ, &ws) == -1) {
  688. #ifdef __sun
  689. /*
  690. * Some versions of Solaris apparently can return an error when
  691. * resizing; don't know why this happens, can't reproduce on
  692. * other platforms and ignoring it doesn't seem to cause any
  693. * issues.
  694. */
  695. if (errno != EINVAL && errno != ENXIO)
  696. #endif
  697. fatal("ioctl failed");
  698. }
  699. wp->flags &= ~PANE_RESIZE;
  700. }
  701. /* Check whether pane should be focused. */
  702. void
  703. server_client_check_focus(struct window_pane *wp)
  704. {
  705. struct client *c;
  706. int push;
  707. /* Are focus events off? */
  708. if (!options_get_number(global_options, "focus-events"))
  709. return;
  710. /* Do we need to push the focus state? */
  711. push = wp->flags & PANE_FOCUSPUSH;
  712. wp->flags &= ~PANE_FOCUSPUSH;
  713. /* If we don't care about focus, forget it. */
  714. if (!(wp->base.mode & MODE_FOCUSON))
  715. return;
  716. /* If we're not the active pane in our window, we're not focused. */
  717. if (wp->window->active != wp)
  718. goto not_focused;
  719. /* If we're in a mode, we're not focused. */
  720. if (wp->screen != &wp->base)
  721. goto not_focused;
  722. /*
  723. * If our window is the current window in any focused clients with an
  724. * attached session, we're focused.
  725. */
  726. TAILQ_FOREACH(c, &clients, entry) {
  727. if (c->session == NULL || !(c->flags & CLIENT_FOCUSED))
  728. continue;
  729. if (c->session->flags & SESSION_UNATTACHED)
  730. continue;
  731. if (c->session->curw->window == wp->window)
  732. goto focused;
  733. }
  734. not_focused:
  735. if (push || (wp->flags & PANE_FOCUSED))
  736. bufferevent_write(wp->event, "\033[O", 3);
  737. wp->flags &= ~PANE_FOCUSED;
  738. return;
  739. focused:
  740. if (push || !(wp->flags & PANE_FOCUSED))
  741. bufferevent_write(wp->event, "\033[I", 3);
  742. wp->flags |= PANE_FOCUSED;
  743. }
  744. /*
  745. * Update cursor position and mode settings. The scroll region and attributes
  746. * are cleared when idle (waiting for an event) as this is the most likely time
  747. * a user may interrupt tmux, for example with ~^Z in ssh(1). This is a
  748. * compromise between excessive resets and likelihood of an interrupt.
  749. *
  750. * tty_region/tty_reset/tty_update_mode already take care of not resetting
  751. * things that are already in their default state.
  752. */
  753. void
  754. server_client_reset_state(struct client *c)
  755. {
  756. struct window *w = c->session->curw->window;
  757. struct window_pane *wp = w->active;
  758. struct screen *s = wp->screen;
  759. struct options *oo = c->session->options;
  760. int status, mode, o;
  761. if (c->flags & CLIENT_SUSPENDED)
  762. return;
  763. if (c->flags & CLIENT_CONTROL)
  764. return;
  765. tty_region(&c->tty, 0, c->tty.sy - 1);
  766. status = options_get_number(oo, "status");
  767. #ifdef TMATE
  768. if (c->flags & CLIENT_FORCE_STATUS)
  769. status = 1;
  770. #endif
  771. if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
  772. tty_cursor(&c->tty, 0, 0);
  773. else {
  774. o = status && options_get_number(oo, "status-position") == 0;
  775. tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy);
  776. }
  777. /*
  778. * Set mouse mode if requested. To support dragging, always use button
  779. * mode.
  780. */
  781. mode = s->mode;
  782. if (options_get_number(oo, "mouse"))
  783. mode = (mode & ~ALL_MOUSE_MODES) | MODE_MOUSE_BUTTON;
  784. /* Set the terminal mode and reset attributes. */
  785. tty_update_mode(&c->tty, mode, s);
  786. tty_reset(&c->tty);
  787. }
  788. /* Repeat time callback. */
  789. void
  790. server_client_repeat_timer(__unused int fd, __unused short events, void *data)
  791. {
  792. struct client *c = data;
  793. if (c->flags & CLIENT_REPEAT) {
  794. server_client_set_key_table(c, NULL);
  795. c->flags &= ~CLIENT_REPEAT;
  796. server_status_client(c);
  797. }
  798. }
  799. /* Check if client should be exited. */
  800. void
  801. server_client_check_exit(struct client *c)
  802. {
  803. if (!(c->flags & CLIENT_EXIT))
  804. return;
  805. if (EVBUFFER_LENGTH(c->stdin_data) != 0)
  806. return;
  807. if (EVBUFFER_LENGTH(c->stdout_data) != 0)
  808. return;
  809. if (EVBUFFER_LENGTH(c->stderr_data) != 0)
  810. return;
  811. proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
  812. c->flags &= ~CLIENT_EXIT;
  813. }
  814. /* Check for client redraws. */
  815. void
  816. server_client_check_redraw(struct client *c)
  817. {
  818. struct session *s = c->session;
  819. struct tty *tty = &c->tty;
  820. struct window_pane *wp;
  821. int flags, redraw;
  822. if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
  823. return;
  824. if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
  825. if (options_get_number(s->options, "set-titles"))
  826. server_client_set_title(c);
  827. if (c->message_string != NULL)
  828. redraw = status_message_redraw(c);
  829. else if (c->prompt_string != NULL)
  830. redraw = status_prompt_redraw(c);
  831. else
  832. redraw = status_redraw(c);
  833. if (!redraw)
  834. c->flags &= ~CLIENT_STATUS;
  835. }
  836. flags = tty->flags & (TTY_FREEZE|TTY_NOCURSOR);
  837. tty->flags = (tty->flags & ~TTY_FREEZE) | TTY_NOCURSOR;
  838. if (c->flags & CLIENT_REDRAW) {
  839. tty_update_mode(tty, tty->mode, NULL);
  840. screen_redraw_screen(c, 1, 1, 1);
  841. c->flags &= ~(CLIENT_STATUS|CLIENT_BORDERS);
  842. } else if (c->flags & CLIENT_REDRAWWINDOW) {
  843. tty_update_mode(tty, tty->mode, NULL);
  844. TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry)
  845. screen_redraw_pane(c, wp);
  846. c->flags &= ~CLIENT_REDRAWWINDOW;
  847. } else {
  848. TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
  849. if (wp->flags & PANE_REDRAW) {
  850. tty_update_mode(tty, tty->mode, NULL);
  851. screen_redraw_pane(c, wp);
  852. }
  853. }
  854. }
  855. if (c->flags & CLIENT_BORDERS) {
  856. tty_update_mode(tty, tty->mode, NULL);
  857. screen_redraw_screen(c, 0, 0, 1);
  858. }
  859. if (c->flags & CLIENT_STATUS) {
  860. tty_update_mode(tty, tty->mode, NULL);
  861. screen_redraw_screen(c, 0, 1, 0);
  862. }
  863. tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags;
  864. tty_update_mode(tty, tty->mode, NULL);
  865. c->flags &= ~(CLIENT_REDRAW|CLIENT_BORDERS|CLIENT_STATUS|
  866. CLIENT_STATUSFORCE);
  867. }
  868. /* Set client title. */
  869. void
  870. server_client_set_title(struct client *c)
  871. {
  872. struct session *s = c->session;
  873. const char *template;
  874. char *title;
  875. struct format_tree *ft;
  876. template = options_get_string(s->options, "set-titles-string");
  877. ft = format_create(NULL, 0);
  878. format_defaults(ft, c, NULL, NULL, NULL);
  879. title = format_expand_time(ft, template, time(NULL));
  880. if (c->title == NULL || strcmp(title, c->title) != 0) {
  881. free(c->title);
  882. c->title = xstrdup(title);
  883. tty_set_title(&c->tty, c->title);
  884. }
  885. free(title);
  886. format_free(ft);
  887. }
  888. /* Dispatch message from client. */
  889. void
  890. server_client_dispatch(struct imsg *imsg, void *arg)
  891. {
  892. struct client *c = arg;
  893. struct msg_stdin_data stdindata;
  894. const char *data;
  895. ssize_t datalen;
  896. struct session *s;
  897. if (c->flags & CLIENT_DEAD)
  898. return;
  899. if (imsg == NULL) {
  900. server_client_lost(c);
  901. return;
  902. }
  903. data = imsg->data;
  904. datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
  905. switch (imsg->hdr.type) {
  906. case MSG_IDENTIFY_FLAGS:
  907. case MSG_IDENTIFY_TERM:
  908. case MSG_IDENTIFY_TTYNAME:
  909. case MSG_IDENTIFY_CWD:
  910. case MSG_IDENTIFY_STDIN:
  911. case MSG_IDENTIFY_ENVIRON:
  912. case MSG_IDENTIFY_CLIENTPID:
  913. case MSG_IDENTIFY_DONE:
  914. server_client_dispatch_identify(c, imsg);
  915. break;
  916. case MSG_COMMAND:
  917. server_client_dispatch_command(c, imsg);
  918. break;
  919. case MSG_STDIN:
  920. if (datalen != sizeof stdindata)
  921. fatalx("bad MSG_STDIN size");
  922. memcpy(&stdindata, data, sizeof stdindata);
  923. if (c->stdin_callback == NULL)
  924. break;
  925. if (stdindata.size <= 0)
  926. c->stdin_closed = 1;
  927. else {
  928. evbuffer_add(c->stdin_data, stdindata.data,
  929. stdindata.size);
  930. }
  931. c->stdin_callback(c, c->stdin_closed,
  932. c->stdin_callback_data);
  933. break;
  934. case MSG_RESIZE:
  935. if (datalen != 0)
  936. fatalx("bad MSG_RESIZE size");
  937. if (c->flags & CLIENT_CONTROL)
  938. break;
  939. if (tty_resize(&c->tty)) {
  940. recalculate_sizes();
  941. server_redraw_client(c);
  942. }
  943. if (c->session != NULL)
  944. hooks_run(c->session->hooks, c, NULL, "client-resized");
  945. break;
  946. case MSG_EXITING:
  947. if (datalen != 0)
  948. fatalx("bad MSG_EXITING size");
  949. c->session = NULL;
  950. tty_close(&c->tty);
  951. proc_send(c->peer, MSG_EXITED, -1, NULL, 0);
  952. break;
  953. case MSG_WAKEUP:
  954. case MSG_UNLOCK:
  955. if (datalen != 0)
  956. fatalx("bad MSG_WAKEUP size");
  957. if (!(c->flags & CLIENT_SUSPENDED))
  958. break;
  959. c->flags &= ~CLIENT_SUSPENDED;
  960. if (c->tty.fd == -1) /* exited in the meantime */
  961. break;
  962. s = c->session;
  963. if (gettimeofday(&c->activity_time, NULL) != 0)
  964. fatal("gettimeofday failed");
  965. if (s != NULL)
  966. session_update_activity(s, &c->activity_time);
  967. tty_start_tty(&c->tty);
  968. server_redraw_client(c);
  969. recalculate_sizes();
  970. break;
  971. case MSG_SHELL:
  972. if (datalen != 0)
  973. fatalx("bad MSG_SHELL size");
  974. server_client_dispatch_shell(c);
  975. break;
  976. }
  977. }
  978. /* Handle command message. */
  979. void
  980. server_client_dispatch_command(struct client *c, struct imsg *imsg)
  981. {
  982. struct msg_command_data data;
  983. char *buf;
  984. size_t len;
  985. struct cmd_list *cmdlist = NULL;
  986. int argc;
  987. char **argv, *cause;
  988. if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data)
  989. fatalx("bad MSG_COMMAND size");
  990. memcpy(&data, imsg->data, sizeof data);
  991. buf = (char *)imsg->data + sizeof data;
  992. len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data;
  993. if (len > 0 && buf[len - 1] != '\0')
  994. fatalx("bad MSG_COMMAND string");
  995. argc = data.argc;
  996. if (cmd_unpack_argv(buf, len, argc, &argv) != 0) {
  997. cmdq_error(c->cmdq, "command too long");
  998. goto error;
  999. }
  1000. if (argc == 0) {
  1001. argc = 1;
  1002. argv = xcalloc(1, sizeof *argv);
  1003. *argv = xstrdup("new-session");
  1004. }
  1005. if ((cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause)) == NULL) {
  1006. cmdq_error(c->cmdq, "%s", cause);
  1007. cmd_free_argv(argc, argv);
  1008. goto error;
  1009. }
  1010. cmd_free_argv(argc, argv);
  1011. if (c != cfg_client || cfg_finished)
  1012. cmdq_run(c->cmdq, cmdlist, NULL);
  1013. else
  1014. cmdq_append(c->cmdq, cmdlist, NULL);
  1015. cmd_list_free(cmdlist);
  1016. return;
  1017. error:
  1018. if (cmdlist != NULL)
  1019. cmd_list_free(cmdlist);
  1020. c->flags |= CLIENT_EXIT;
  1021. }
  1022. /* Handle identify message. */
  1023. void
  1024. server_client_dispatch_identify(struct client *c, struct imsg *imsg)
  1025. {
  1026. const char *data, *home;
  1027. size_t datalen;
  1028. int flags;
  1029. if (c->flags & CLIENT_IDENTIFIED)
  1030. fatalx("out-of-order identify message");
  1031. data = imsg->data;
  1032. datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
  1033. switch (imsg->hdr.type) {
  1034. case MSG_IDENTIFY_FLAGS:
  1035. if (datalen != sizeof flags)
  1036. fatalx("bad MSG_IDENTIFY_FLAGS size");
  1037. memcpy(&flags, data, sizeof flags);
  1038. c->flags |= flags;
  1039. log_debug("client %p IDENTIFY_FLAGS %#x", c, flags);
  1040. break;
  1041. case MSG_IDENTIFY_TERM:
  1042. if (datalen == 0 || data[datalen - 1] != '\0')
  1043. fatalx("bad MSG_IDENTIFY_TERM string");
  1044. c->term = xstrdup(data);
  1045. log_debug("client %p IDENTIFY_TERM %s", c, data);
  1046. break;
  1047. case MSG_IDENTIFY_TTYNAME:
  1048. if (datalen == 0 || data[datalen - 1] != '\0')
  1049. fatalx("bad MSG_IDENTIFY_TTYNAME string");
  1050. c->ttyname = xstrdup(data);
  1051. log_debug("client %p IDENTIFY_TTYNAME %s", c, data);
  1052. break;
  1053. case MSG_IDENTIFY_CWD:
  1054. if (datalen == 0 || data[datalen - 1] != '\0')
  1055. fatalx("bad MSG_IDENTIFY_CWD string");
  1056. if (access(data, X_OK) == 0)
  1057. c->cwd = xstrdup(data);
  1058. else if ((home = find_home()) != NULL)
  1059. c->cwd = xstrdup(home);
  1060. else
  1061. c->cwd = xstrdup("/");
  1062. log_debug("client %p IDENTIFY_CWD %s", c, data);
  1063. break;
  1064. case MSG_IDENTIFY_STDIN:
  1065. if (datalen != 0)
  1066. fatalx("bad MSG_IDENTIFY_STDIN size");
  1067. c->fd = imsg->fd;
  1068. log_debug("client %p IDENTIFY_STDIN %d", c, imsg->fd);
  1069. break;
  1070. case MSG_IDENTIFY_ENVIRON:
  1071. if (datalen == 0 || data[datalen - 1] != '\0')
  1072. fatalx("bad MSG_IDENTIFY_ENVIRON string");
  1073. if (strchr(data, '=') != NULL)
  1074. environ_put(c->environ, data);
  1075. log_debug("client %p IDENTIFY_ENVIRON %s", c, data);
  1076. break;
  1077. case MSG_IDENTIFY_CLIENTPID:
  1078. if (datalen != sizeof c->pid)
  1079. fatalx("bad MSG_IDENTIFY_CLIENTPID size");
  1080. memcpy(&c->pid, data, sizeof c->pid);
  1081. log_debug("client %p IDENTIFY_CLIENTPID %ld", c, (long)c->pid);
  1082. break;
  1083. default:
  1084. break;
  1085. }
  1086. if (imsg->hdr.type != MSG_IDENTIFY_DONE)
  1087. return;
  1088. c->flags |= CLIENT_IDENTIFIED;
  1089. #ifdef __CYGWIN__
  1090. c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
  1091. #endif
  1092. if (c->flags & CLIENT_CONTROL) {
  1093. c->stdin_callback = control_callback;
  1094. evbuffer_free(c->stderr_data);
  1095. c->stderr_data = c->stdout_data;
  1096. if (c->flags & CLIENT_CONTROLCONTROL)
  1097. evbuffer_add_printf(c->stdout_data, "\033P1000p");
  1098. proc_send(c->peer, MSG_STDIN, -1, NULL, 0);
  1099. c->tty.fd = -1;
  1100. close(c->fd);
  1101. c->fd = -1;
  1102. return;
  1103. }
  1104. if (c->fd == -1)
  1105. return;
  1106. if (tty_init(&c->tty, c, c->fd, c->term) != 0) {
  1107. close(c->fd);
  1108. c->fd = -1;
  1109. return;
  1110. }
  1111. if (c->flags & CLIENT_UTF8)
  1112. c->tty.flags |= TTY_UTF8;
  1113. if (c->flags & CLIENT_256COLOURS)
  1114. c->tty.term_flags |= TERM_256COLOURS;
  1115. tty_resize(&c->tty);
  1116. if (!(c->flags & CLIENT_CONTROL))
  1117. c->flags |= CLIENT_TERMINAL;
  1118. }
  1119. /* Handle shell message. */
  1120. void
  1121. server_client_dispatch_shell(struct client *c)
  1122. {
  1123. const char *shell;
  1124. shell = options_get_string(global_s_options, "default-shell");
  1125. if (*shell == '\0' || areshell(shell))
  1126. shell = _PATH_BSHELL;
  1127. proc_send_s(c->peer, MSG_SHELL, shell);
  1128. proc_kill_peer(c->peer);
  1129. }
  1130. /* Event callback to push more stdout data if any left. */
  1131. static void
  1132. server_client_stdout_cb(__unused int fd, __unused short events, void *arg)
  1133. {
  1134. struct client *c = arg;
  1135. if (~c->flags & CLIENT_DEAD)
  1136. server_client_push_stdout(c);
  1137. server_client_unref(c);
  1138. }
  1139. /* Push stdout to client if possible. */
  1140. void
  1141. server_client_push_stdout(struct client *c)
  1142. {
  1143. struct msg_stdout_data data;
  1144. size_t sent, left;
  1145. left = EVBUFFER_LENGTH(c->stdout_data);
  1146. while (left != 0) {
  1147. sent = left;
  1148. if (sent > sizeof data.data)
  1149. sent = sizeof data.data;
  1150. memcpy(data.data, EVBUFFER_DATA(c->stdout_data), sent);
  1151. data.size = sent;
  1152. if (proc_send(c->peer, MSG_STDOUT, -1, &data, sizeof data) != 0)
  1153. break;
  1154. evbuffer_drain(c->stdout_data, sent);
  1155. left = EVBUFFER_LENGTH(c->stdout_data);
  1156. log_debug("%s: client %p, sent %zu, left %zu", __func__, c,
  1157. sent, left);
  1158. }
  1159. if (left != 0) {
  1160. c->references++;
  1161. event_once(-1, EV_TIMEOUT, server_client_stdout_cb, c, NULL);
  1162. log_debug("%s: client %p, queued", __func__, c);
  1163. }
  1164. }
  1165. /* Event callback to push more stderr data if any left. */
  1166. static void
  1167. server_client_stderr_cb(__unused int fd, __unused short events, void *arg)
  1168. {
  1169. struct client *c = arg;
  1170. if (~c->flags & CLIENT_DEAD)
  1171. server_client_push_stderr(c);
  1172. server_client_unref(c);
  1173. }
  1174. /* Push stderr to client if possible. */
  1175. void
  1176. server_client_push_stderr(struct client *c)
  1177. {
  1178. struct msg_stderr_data data;
  1179. size_t sent, left;
  1180. if (c->stderr_data == c->stdout_data) {
  1181. server_client_push_stdout(c);
  1182. return;
  1183. }
  1184. left = EVBUFFER_LENGTH(c->stderr_data);
  1185. while (left != 0) {
  1186. sent = left;
  1187. if (sent > sizeof data.data)
  1188. sent = sizeof data.data;
  1189. memcpy(data.data, EVBUFFER_DATA(c->stderr_data), sent);
  1190. data.size = sent;
  1191. if (proc_send(c->peer, MSG_STDERR, -1, &data, sizeof data) != 0)
  1192. break;
  1193. evbuffer_drain(c->stderr_data, sent);
  1194. left = EVBUFFER_LENGTH(c->stderr_data);
  1195. log_debug("%s: client %p, sent %zu, left %zu", __func__, c,
  1196. sent, left);
  1197. }
  1198. if (left != 0) {
  1199. c->references++;
  1200. event_once(-1, EV_TIMEOUT, server_client_stderr_cb, c, NULL);
  1201. log_debug("%s: client %p, queued", __func__, c);
  1202. }
  1203. }