Annotation of src/usr.bin/tmux/server.c, Revision 1.18
1.18 ! nicm 1: /* $OpenBSD: server.c,v 1.17 2009/08/10 19:42:03 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2007 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: #include <sys/ioctl.h>
21: #include <sys/socket.h>
22: #include <sys/stat.h>
23: #include <sys/un.h>
24: #include <sys/wait.h>
25:
26: #include <errno.h>
27: #include <fcntl.h>
1.5 nicm 28: #include <paths.h>
1.1 nicm 29: #include <signal.h>
30: #include <stdio.h>
31: #include <stdlib.h>
32: #include <string.h>
33: #include <syslog.h>
34: #include <termios.h>
35: #include <time.h>
36: #include <unistd.h>
37:
38: #include "tmux.h"
39:
40: /*
41: * Main server functions.
42: */
43:
44: /* Client list. */
45: struct clients clients;
46:
1.13 nicm 47: void server_create_client(int);
1.1 nicm 48: int server_create_socket(void);
49: int server_main(int);
50: void server_shutdown(void);
51: void server_child_signal(void);
52: void server_fill_windows(struct pollfd **);
53: void server_handle_windows(struct pollfd **);
54: void server_fill_clients(struct pollfd **);
55: void server_handle_clients(struct pollfd **);
1.13 nicm 56: void server_accept_client(int);
1.1 nicm 57: void server_handle_client(struct client *);
58: void server_handle_window(struct window *, struct window_pane *);
1.10 nicm 59: int server_check_window_bell(struct session *, struct window *);
1.1 nicm 60: int server_check_window_activity(struct session *,
61: struct window *);
62: int server_check_window_content(struct session *, struct window *,
63: struct window_pane *);
64: void server_lost_client(struct client *);
65: void server_check_window(struct window *);
66: void server_check_redraw(struct client *);
67: void server_redraw_locked(struct client *);
68: void server_check_timers(struct client *);
69: void server_second_timers(void);
70: int server_update_socket(void);
71:
72: /* Create a new client. */
1.13 nicm 73: void
1.1 nicm 74: server_create_client(int fd)
75: {
76: struct client *c;
77: int mode;
78: u_int i;
79:
80: if ((mode = fcntl(fd, F_GETFL)) == -1)
81: fatal("fcntl failed");
82: if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
83: fatal("fcntl failed");
84: if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
85: fatal("fcntl failed");
86:
87: c = xcalloc(1, sizeof *c);
1.18 ! nicm 88: imsg_init(&c->ibuf, fd);
1.1 nicm 89:
90: ARRAY_INIT(&c->prompt_hdata);
91:
92: c->tty.fd = -1;
93: c->title = NULL;
94:
95: c->session = NULL;
96: c->tty.sx = 80;
97: c->tty.sy = 25;
98: screen_init(&c->status, c->tty.sx, 1, 0);
99:
100: c->message_string = NULL;
101:
102: c->prompt_string = NULL;
103: c->prompt_buffer = NULL;
104: c->prompt_index = 0;
105:
106: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
107: if (ARRAY_ITEM(&clients, i) == NULL) {
108: ARRAY_SET(&clients, i, c);
1.13 nicm 109: return;
1.1 nicm 110: }
111: }
112: ARRAY_ADD(&clients, c);
113: }
114:
115: /* Find client index. */
116: int
117: server_client_index(struct client *c)
118: {
119: u_int i;
120:
121: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
122: if (c == ARRAY_ITEM(&clients, i))
123: return (i);
124: }
125: return (-1);
126: }
127:
128: /* Fork new server. */
129: int
130: server_start(char *path)
131: {
1.16 nicm 132: struct client *c;
133: int pair[2], srv_fd;
134: char *cause;
135: char rpathbuf[MAXPATHLEN];
1.1 nicm 136:
137: /* The first client is special and gets a socketpair; create it. */
138: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
139: fatal("socketpair failed");
140:
141: switch (fork()) {
142: case -1:
143: fatal("fork failed");
144: case 0:
145: break;
146: default:
147: close(pair[1]);
148: return (pair[0]);
149: }
150: close(pair[0]);
151:
152: /*
153: * Must daemonise before loading configuration as the PID changes so
154: * $TMUX would be wrong for sessions created in the config file.
155: */
1.16 nicm 156: if (daemon(1, 0) != 0)
1.1 nicm 157: fatal("daemon failed");
158:
1.16 nicm 159: logfile("server");
160: log_debug("server started, pid %ld", (long) getpid());
161:
1.1 nicm 162: ARRAY_INIT(&windows);
163: ARRAY_INIT(&clients);
164: ARRAY_INIT(&sessions);
1.15 nicm 165: mode_key_init_trees();
1.1 nicm 166: key_bindings_init();
167: utf8_build();
168:
169: server_locked = 0;
170: server_password = NULL;
171: server_activity = time(NULL);
172:
173: start_time = time(NULL);
174: socket_path = path;
175:
1.16 nicm 176: if (realpath(socket_path, rpathbuf) == NULL)
177: strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
178: log_debug("socket path %s", socket_path);
179: setproctitle("server (%s)", rpathbuf);
180:
181: srv_fd = server_create_socket();
182: server_create_client(pair[1]);
183:
1.7 nicm 184: if (access(SYSTEM_CFG, R_OK) != 0) {
185: if (errno != ENOENT) {
1.16 nicm 186: xasprintf(
187: &cause, "%s: %s", strerror(errno), SYSTEM_CFG);
188: goto error;
189: }
190: } else if (load_cfg(SYSTEM_CFG, &cause) != 0)
191: goto error;
192: if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0)
193: goto error;
1.5 nicm 194:
1.16 nicm 195: exit(server_main(srv_fd));
1.1 nicm 196:
1.16 nicm 197: error:
198: /* Write the error and shutdown the server. */
199: c = ARRAY_FIRST(&clients);
1.1 nicm 200:
1.16 nicm 201: server_write_error(c, cause);
202: xfree(cause);
1.1 nicm 203:
1.16 nicm 204: server_shutdown();
205: c->flags |= CLIENT_BAD;
1.1 nicm 206:
207: exit(server_main(srv_fd));
208: }
209:
210: /* Create server socket. */
211: int
212: server_create_socket(void)
213: {
214: struct sockaddr_un sa;
215: size_t size;
216: mode_t mask;
217: int fd, mode;
218:
219: memset(&sa, 0, sizeof sa);
220: sa.sun_family = AF_UNIX;
221: size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
222: if (size >= sizeof sa.sun_path) {
223: errno = ENAMETOOLONG;
224: fatal("socket failed");
225: }
226: unlink(sa.sun_path);
227:
228: if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
229: fatal("socket failed");
230:
231: mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
232: if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
233: fatal("bind failed");
234: umask(mask);
235:
236: if (listen(fd, 16) == -1)
237: fatal("listen failed");
238:
239: if ((mode = fcntl(fd, F_GETFL)) == -1)
240: fatal("fcntl failed");
241: if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
242: fatal("fcntl failed");
243: if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
244: fatal("fcntl failed");
245:
246: return (fd);
247: }
248:
249: /* Main server loop. */
250: int
251: server_main(int srv_fd)
252: {
253: struct window *w;
254: struct pollfd *pfds, *pfd;
255: int nfds, xtimeout;
256: u_int i, n;
257: time_t now, last;
258:
259: siginit();
260:
261: last = time(NULL);
262:
263: pfds = NULL;
264: for (;;) {
265: /* If sigterm, kill all windows and clients. */
266: if (sigterm)
267: server_shutdown();
268:
269: /* Handle child exit. */
270: if (sigchld) {
271: server_child_signal();
272: sigchld = 0;
273: }
274:
275: /* Recreate socket on SIGUSR1. */
276: if (sigusr1) {
277: close(srv_fd);
278: srv_fd = server_create_socket();
279: sigusr1 = 0;
280: }
281:
282: /* Initialise pollfd array. */
283: nfds = 1;
284: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
285: w = ARRAY_ITEM(&windows, i);
286: if (w != NULL)
287: nfds += window_count_panes(w);
288: }
289: nfds += ARRAY_LENGTH(&clients) * 2;
290: pfds = xrealloc(pfds, nfds, sizeof *pfds);
291: memset(pfds, 0, nfds * sizeof *pfds);
292: pfd = pfds;
293:
294: /* Fill server socket. */
295: pfd->fd = srv_fd;
296: pfd->events = POLLIN;
297: pfd++;
298:
299: /* Fill window and client sockets. */
300: server_fill_windows(&pfd);
301: server_fill_clients(&pfd);
302:
303: /* Update socket permissions. */
304: xtimeout = INFTIM;
305: if (sigterm || server_update_socket() != 0)
306: xtimeout = POLL_TIMEOUT;
307:
308: /* Do the poll. */
1.4 nicm 309: if (poll(pfds, nfds, xtimeout) == -1) {
1.1 nicm 310: if (errno == EAGAIN || errno == EINTR)
311: continue;
312: fatal("poll failed");
313: }
314: pfd = pfds;
315:
316: /* Handle server socket. */
317: if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
318: fatalx("lost server socket");
319: if (pfd->revents & POLLIN) {
320: server_accept_client(srv_fd);
321: continue;
322: }
323: pfd++;
324:
325: /* Call second-based timers. */
326: now = time(NULL);
327: if (now != last) {
328: last = now;
329: server_second_timers();
330: }
331:
332: /* Set window names. */
333: set_window_names();
334:
335: /*
336: * Handle window and client sockets. Clients can create
337: * windows, so windows must come first to avoid messing up by
338: * increasing the array size.
339: */
340: server_handle_windows(&pfd);
341: server_handle_clients(&pfd);
342:
1.8 nicm 343: /* Collect any unset key bindings. */
344: key_bindings_clean();
345:
1.1 nicm 346: /*
347: * If we have no sessions and clients left, let's get out
348: * of here...
349: */
350: n = 0;
351: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
352: if (ARRAY_ITEM(&sessions, i) != NULL)
353: n++;
354: }
355: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
356: if (ARRAY_ITEM(&clients, i) != NULL)
357: n++;
358: }
359: if (n == 0)
360: break;
361: }
362: if (pfds != NULL)
363: xfree(pfds);
364:
365: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
366: if (ARRAY_ITEM(&sessions, i) != NULL)
367: session_destroy(ARRAY_ITEM(&sessions, i));
368: }
369: ARRAY_FREE(&sessions);
370:
371: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
372: if (ARRAY_ITEM(&clients, i) != NULL)
373: server_lost_client(ARRAY_ITEM(&clients, i));
374: }
375: ARRAY_FREE(&clients);
376:
1.15 nicm 377: mode_key_free_trees();
1.1 nicm 378: key_bindings_free();
379:
380: close(srv_fd);
381:
382: unlink(socket_path);
383: xfree(socket_path);
384:
1.6 nicm 385: options_free(&global_s_options);
386: options_free(&global_w_options);
1.1 nicm 387: if (server_password != NULL)
388: xfree(server_password);
389:
390: return (0);
391: }
392:
393: /* Kill all clients. */
394: void
395: server_shutdown(void)
396: {
397: struct session *s;
398: struct client *c;
399: u_int i, j;
400:
401: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
402: s = ARRAY_ITEM(&sessions, i);
403: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
404: c = ARRAY_ITEM(&clients, j);
405: if (c != NULL && c->session == s) {
406: s = NULL;
407: break;
408: }
409: }
410: if (s != NULL)
411: session_destroy(s);
412: }
413:
414: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
415: c = ARRAY_ITEM(&clients, i);
1.16 nicm 416: if (c != NULL) {
417: if (c->flags & CLIENT_BAD)
418: server_lost_client(c);
419: else
420: server_write_client(c, MSG_SHUTDOWN, NULL, 0);
421: c->flags |= CLIENT_BAD;
422: }
1.1 nicm 423: }
424: }
425:
426: /* Handle SIGCHLD. */
427: void
428: server_child_signal(void)
429: {
430: struct window *w;
431: struct window_pane *wp;
432: int status;
433: pid_t pid;
434: u_int i;
435:
436: for (;;) {
437: switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
438: case -1:
439: if (errno == ECHILD)
440: return;
441: fatal("waitpid");
442: case 0:
443: return;
444: }
445: if (!WIFSTOPPED(status))
446: continue;
447: if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
448: continue;
449:
450: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
451: w = ARRAY_ITEM(&windows, i);
452: if (w == NULL)
453: continue;
454: TAILQ_FOREACH(wp, &w->panes, entry) {
455: if (wp->pid == pid) {
456: if (killpg(pid, SIGCONT) != 0)
457: kill(pid, SIGCONT);
458: }
459: }
460: }
461: }
462: }
463:
464: /* Fill window pollfds. */
465: void
466: server_fill_windows(struct pollfd **pfd)
467: {
468: struct window *w;
469: struct window_pane *wp;
470: u_int i;
471:
472: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
473: w = ARRAY_ITEM(&windows, i);
474: if (w == NULL)
475: continue;
476:
477: TAILQ_FOREACH(wp, &w->panes, entry) {
478: (*pfd)->fd = wp->fd;
479: if (wp->fd != -1) {
480: (*pfd)->events = POLLIN;
481: if (BUFFER_USED(wp->out) > 0)
482: (*pfd)->events |= POLLOUT;
483: }
484: (*pfd)++;
485: }
486: }
487: }
488:
489: /* Handle window pollfds. */
490: void
491: server_handle_windows(struct pollfd **pfd)
492: {
493: struct window *w;
494: struct window_pane *wp;
495: u_int i;
496:
497: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
498: w = ARRAY_ITEM(&windows, i);
499: if (w == NULL)
500: continue;
501:
502: TAILQ_FOREACH(wp, &w->panes, entry) {
503: if (wp->fd != -1) {
504: if (buffer_poll(*pfd, wp->in, wp->out) != 0) {
505: close(wp->fd);
506: wp->fd = -1;
507: } else
508: server_handle_window(w, wp);
509: }
510: (*pfd)++;
511: }
512:
513: server_check_window(w);
514: }
515: }
516:
517: /* Check for general redraw on client. */
518: void
519: server_check_redraw(struct client *c)
520: {
521: struct session *s;
522: struct window_pane *wp;
523: char title[512];
524: int flags, redraw;
525:
526: if (c == NULL || c->session == NULL)
527: return;
528: s = c->session;
529:
530: flags = c->tty.flags & TTY_FREEZE;
531: c->tty.flags &= ~TTY_FREEZE;
532:
533: if (options_get_number(&s->options, "set-titles")) {
534: xsnprintf(title, sizeof title, "%s:%u:%s - \"%s\"",
535: s->name, s->curw->idx, s->curw->window->name,
536: s->curw->window->active->screen->title);
537: if (c->title == NULL || strcmp(title, c->title) != 0) {
538: if (c->title != NULL)
539: xfree(c->title);
540: c->title = xstrdup(title);
541: tty_set_title(&c->tty, c->title);
542: }
543: }
544:
545: if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
546: if (c->message_string != NULL)
547: redraw = status_message_redraw(c);
548: else if (c->prompt_string != NULL)
549: redraw = status_prompt_redraw(c);
550: else
551: redraw = status_redraw(c);
552: if (!redraw)
553: c->flags &= ~CLIENT_STATUS;
554: }
555:
556: if (c->flags & CLIENT_REDRAW) {
557: if (server_locked)
558: server_redraw_locked(c);
559: else
1.9 nicm 560: screen_redraw_screen(c, 0);
1.1 nicm 561: c->flags &= ~CLIENT_STATUS;
562: } else {
563: TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
564: if (wp->flags & PANE_REDRAW)
565: screen_redraw_pane(c, wp);
566: }
567: }
568:
569: if (c->flags & CLIENT_STATUS)
1.9 nicm 570: screen_redraw_screen(c, 1);
1.1 nicm 571:
572: c->tty.flags |= flags;
573:
574: c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS);
575: }
576:
577: /* Redraw client when locked. */
578: void
579: server_redraw_locked(struct client *c)
580: {
581: struct screen_write_ctx ctx;
582: struct screen screen;
1.12 nicm 583: struct grid_cell gc;
1.1 nicm 584: u_int colour, xx, yy, i;
585: int style;
586:
587: xx = c->tty.sx;
588: yy = c->tty.sy - 1;
589: if (xx == 0 || yy == 0)
590: return;
1.6 nicm 591: colour = options_get_number(&global_w_options, "clock-mode-colour");
592: style = options_get_number(&global_w_options, "clock-mode-style");
1.1 nicm 593:
1.12 nicm 594: memcpy(&gc, &grid_default_cell, sizeof gc);
595: gc.fg = colour;
596: gc.attr |= GRID_ATTR_BRIGHT;
597:
1.1 nicm 598: screen_init(&screen, xx, yy, 0);
599:
600: screen_write_start(&ctx, NULL, &screen);
601: clock_draw(&ctx, colour, style);
1.12 nicm 602:
603: if (password_failures != 0) {
604: screen_write_cursormove(&ctx, 0, 0);
605: screen_write_puts(
606: &ctx, &gc, "%u failed attempts", password_failures);
607: }
608:
1.1 nicm 609: screen_write_stop(&ctx);
610:
611: for (i = 0; i < screen_size_y(&screen); i++)
612: tty_draw_line(&c->tty, &screen, i, 0, 0);
1.9 nicm 613: screen_redraw_screen(c, 1);
1.1 nicm 614:
615: screen_free(&screen);
616: }
617:
618: /* Check for timers on client. */
619: void
620: server_check_timers(struct client *c)
621: {
622: struct session *s;
623: struct timeval tv;
624: u_int interval;
625:
626: if (c == NULL || c->session == NULL)
627: return;
628: s = c->session;
629:
630: if (gettimeofday(&tv, NULL) != 0)
631: fatal("gettimeofday");
632:
633: if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >))
634: status_message_clear(c);
635:
636: if (c->message_string != NULL || c->prompt_string != NULL) {
637: /*
638: * Don't need timed redraw for messages/prompts so bail now.
639: * The status timer isn't reset when they are redrawn anyway.
640: */
641: return;
642: }
643: if (!options_get_number(&s->options, "status"))
644: return;
645:
646: /* Check timer; resolution is only a second so don't be too clever. */
647: interval = options_get_number(&s->options, "status-interval");
648: if (interval == 0)
649: return;
650: if (tv.tv_sec < c->status_timer.tv_sec ||
651: ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval)
652: c->flags |= CLIENT_STATUS;
653: }
654:
655: /* Fill client pollfds. */
656: void
657: server_fill_clients(struct pollfd **pfd)
658: {
659: struct client *c;
660: struct window *w;
661: struct window_pane *wp;
662: u_int i;
663:
664: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
665: c = ARRAY_ITEM(&clients, i);
666:
667: server_check_timers(c);
668: server_check_redraw(c);
669:
670: if (c == NULL)
671: (*pfd)->fd = -1;
672: else {
1.18 ! nicm 673: (*pfd)->fd = c->ibuf.fd;
1.16 nicm 674: if (!(c->flags & CLIENT_BAD))
1.18 ! nicm 675: (*pfd)->events |= POLLIN;
! 676: if (c->ibuf.w.queued > 0)
1.1 nicm 677: (*pfd)->events |= POLLOUT;
678: }
679: (*pfd)++;
680:
681: if (c == NULL || c->flags & CLIENT_SUSPENDED ||
682: c->tty.fd == -1 || c->session == NULL)
683: (*pfd)->fd = -1;
684: else {
685: (*pfd)->fd = c->tty.fd;
686: (*pfd)->events = POLLIN;
687: if (BUFFER_USED(c->tty.out) > 0)
688: (*pfd)->events |= POLLOUT;
689: }
690: (*pfd)++;
691: }
692:
693: /*
694: * Clear any window redraw flags (will have been redrawn as part of
695: * client).
696: */
697: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
698: w = ARRAY_ITEM(&windows, i);
699: if (w == NULL)
700: continue;
701:
702: w->flags &= ~WINDOW_REDRAW;
703: TAILQ_FOREACH(wp, &w->panes, entry)
704: wp->flags &= ~PANE_REDRAW;
705: }
706: }
707:
708: /* Handle client pollfds. */
709: void
710: server_handle_clients(struct pollfd **pfd)
711: {
712: struct client *c;
713: u_int i;
714:
715: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
716: c = ARRAY_ITEM(&clients, i);
717:
718: if (c != NULL) {
1.18 ! nicm 719: if ((*pfd)->revents & (POLLERR|POLLNVAL|POLLHUP)) {
1.1 nicm 720: server_lost_client(c);
721: (*pfd) += 2;
722: continue;
1.18 ! nicm 723: }
! 724:
! 725: if ((*pfd)->revents & POLLOUT) {
! 726: if (msgbuf_write(&c->ibuf.w) < 0) {
! 727: server_lost_client(c);
! 728: (*pfd) += 2;
! 729: continue;
! 730: }
! 731: }
! 732:
! 733: if (c->flags & CLIENT_BAD) {
! 734: if (c->ibuf.w.queued == 0)
1.16 nicm 735: server_lost_client(c);
736: (*pfd) += 2;
1.18 ! nicm 737: continue;
! 738: } else if ((*pfd)->revents & POLLIN) {
! 739: if (server_msg_dispatch(c) != 0) {
! 740: server_lost_client(c);
! 741: (*pfd) += 2;
! 742: continue;
! 743: }
! 744: }
1.1 nicm 745: }
746: (*pfd)++;
747:
748: if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
749: c->tty.fd != -1 && c->session != NULL) {
750: if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0)
751: server_lost_client(c);
752: else
753: server_handle_client(c);
754: }
755: (*pfd)++;
756: }
757: }
758:
759: /* accept(2) and create new client. */
1.13 nicm 760: void
1.1 nicm 761: server_accept_client(int srv_fd)
762: {
763: struct sockaddr_storage sa;
764: socklen_t slen = sizeof sa;
765: int fd;
766:
767: fd = accept(srv_fd, (struct sockaddr *) &sa, &slen);
768: if (fd == -1) {
769: if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
1.13 nicm 770: return;
1.1 nicm 771: fatal("accept failed");
772: }
773: if (sigterm) {
774: close(fd);
1.13 nicm 775: return;
1.1 nicm 776: }
1.13 nicm 777: server_create_client(fd);
1.1 nicm 778: }
779:
780: /* Input data from client. */
781: void
782: server_handle_client(struct client *c)
783: {
784: struct window_pane *wp;
785: struct screen *s;
786: struct timeval tv;
787: struct key_binding *bd;
788: int key, prefix, status, xtimeout;
789: int mode;
790: u_char mouse[3];
791:
792: xtimeout = options_get_number(&c->session->options, "repeat-time");
793: if (xtimeout != 0 && c->flags & CLIENT_REPEAT) {
794: if (gettimeofday(&tv, NULL) != 0)
795: fatal("gettimeofday");
796: if (timercmp(&tv, &c->repeat_timer, >))
797: c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
798: }
799:
800: /* Process keys. */
801: prefix = options_get_number(&c->session->options, "prefix");
802: while (tty_keys_next(&c->tty, &key, mouse) == 0) {
803: server_activity = time(NULL);
804:
805: if (c->session == NULL)
806: return;
807: wp = c->session->curw->window->active; /* could die */
808:
809: status_message_clear(c);
810: if (c->prompt_string != NULL) {
811: status_prompt_key(c, key);
812: continue;
813: }
814: if (server_locked)
815: continue;
816:
817: /* Check for mouse keys. */
818: if (key == KEYC_MOUSE) {
819: window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]);
820: continue;
821: }
822:
823: /* No previous prefix key. */
824: if (!(c->flags & CLIENT_PREFIX)) {
825: if (key == prefix)
826: c->flags |= CLIENT_PREFIX;
1.14 nicm 827: else {
828: /* Try as a non-prefix key binding. */
829: if ((bd = key_bindings_lookup(key)) == NULL)
830: window_pane_key(wp, c, key);
831: else
832: key_bindings_dispatch(bd, c);
833: }
1.1 nicm 834: continue;
835: }
836:
837: /* Prefix key already pressed. Reset prefix and lookup key. */
838: c->flags &= ~CLIENT_PREFIX;
1.14 nicm 839: if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) {
1.1 nicm 840: /* If repeating, treat this as a key, else ignore. */
841: if (c->flags & CLIENT_REPEAT) {
842: c->flags &= ~CLIENT_REPEAT;
843: if (key == prefix)
844: c->flags |= CLIENT_PREFIX;
845: else
846: window_pane_key(wp, c, key);
847: }
848: continue;
849: }
850:
851: /* If already repeating, but this key can't repeat, skip it. */
852: if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
853: c->flags &= ~CLIENT_REPEAT;
854: if (key == prefix)
855: c->flags |= CLIENT_PREFIX;
856: else
857: window_pane_key(wp, c, key);
858: continue;
859: }
860:
861: /* If this key can repeat, reset the repeat flags and timer. */
862: if (xtimeout != 0 && bd->can_repeat) {
863: c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
864:
865: tv.tv_sec = xtimeout / 1000;
866: tv.tv_usec = (xtimeout % 1000) * 1000L;
867: if (gettimeofday(&c->repeat_timer, NULL) != 0)
868: fatal("gettimeofday");
869: timeradd(&c->repeat_timer, &tv, &c->repeat_timer);
870: }
871:
872: /* Dispatch the command. */
873: key_bindings_dispatch(bd, c);
874: }
875: if (c->session == NULL)
876: return;
877: wp = c->session->curw->window->active; /* could die - do each loop */
878: s = wp->screen;
879:
880: /* Ensure cursor position and mode settings. */
881: status = options_get_number(&c->session->options, "status");
1.17 nicm 882: tty_region(&c->tty, 0, c->tty.sy - 1, 0);
1.11 nicm 883: if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status)
884: tty_cursor(&c->tty, 0, 0, 0, 0);
885: else
1.1 nicm 886: tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff);
887:
888: mode = s->mode;
889: if (server_locked)
890: mode &= ~TTY_NOCURSOR;
891: tty_update_mode(&c->tty, mode);
892: }
893:
894: /* Lost a client. */
895: void
896: server_lost_client(struct client *c)
897: {
898: u_int i;
899:
900: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
901: if (ARRAY_ITEM(&clients, i) == c)
902: ARRAY_SET(&clients, i, NULL);
903: }
904:
905: tty_free(&c->tty, c->flags & CLIENT_SUSPENDED);
906:
907: screen_free(&c->status);
908:
909: if (c->title != NULL)
910: xfree(c->title);
911:
912: if (c->message_string != NULL)
913: xfree(c->message_string);
914:
915: if (c->prompt_string != NULL)
916: xfree(c->prompt_string);
917: if (c->prompt_buffer != NULL)
918: xfree(c->prompt_buffer);
919: for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
920: xfree(ARRAY_ITEM(&c->prompt_hdata, i));
921: ARRAY_FREE(&c->prompt_hdata);
922:
923: if (c->cwd != NULL)
924: xfree(c->cwd);
925:
1.18 ! nicm 926: close(c->ibuf.fd);
! 927: imsg_clear(&c->ibuf);
1.1 nicm 928: xfree(c);
929:
930: recalculate_sizes();
931: }
932:
933: /* Handle window data. */
934: void
935: server_handle_window(struct window *w, struct window_pane *wp)
936: {
937: struct session *s;
938: u_int i;
939: int update;
940:
941: window_pane_parse(wp);
942:
943: if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0)
944: return;
945:
946: update = 0;
947: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
948: s = ARRAY_ITEM(&sessions, i);
949: if (s == NULL || !session_has(s, w))
950: continue;
951:
1.10 nicm 952: update += server_check_window_bell(s, w);
1.1 nicm 953: update += server_check_window_activity(s, w);
954: update += server_check_window_content(s, w, wp);
955: }
956: if (update)
957: server_status_window(w);
958:
959: w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
960: }
961:
962: int
1.10 nicm 963: server_check_window_bell(struct session *s, struct window *w)
1.1 nicm 964: {
965: struct client *c;
966: u_int i;
1.10 nicm 967: int action, visual;
1.1 nicm 968:
969: if (!(w->flags & WINDOW_BELL))
970: return (0);
971: if (session_alert_has_window(s, w, WINDOW_BELL))
972: return (0);
973: session_alert_add(s, w, WINDOW_BELL);
974:
975: action = options_get_number(&s->options, "bell-action");
976: switch (action) {
977: case BELL_ANY:
978: if (s->flags & SESSION_UNATTACHED)
979: break;
1.10 nicm 980: visual = options_get_number(&s->options, "visual-bell");
1.1 nicm 981: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
982: c = ARRAY_ITEM(&clients, i);
1.10 nicm 983: if (c == NULL || c->session != s)
984: continue;
985: if (!visual) {
1.1 nicm 986: tty_putcode(&c->tty, TTYC_BEL);
1.10 nicm 987: continue;
988: }
989: if (c->session->curw->window == w) {
990: status_message_set(c, "Bell in current window");
991: continue;
992: }
993: status_message_set(c, "Bell in window %u",
994: winlink_find_by_window(&s->windows, w)->idx);
1.1 nicm 995: }
996: break;
997: case BELL_CURRENT:
1.10 nicm 998: if (s->flags & SESSION_UNATTACHED)
1.1 nicm 999: break;
1.10 nicm 1000: visual = options_get_number(&s->options, "visual-bell");
1.1 nicm 1001: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1002: c = ARRAY_ITEM(&clients, i);
1.10 nicm 1003: if (c == NULL || c->session != s)
1004: continue;
1005: if (c->session->curw->window != w)
1006: continue;
1007: if (!visual) {
1.1 nicm 1008: tty_putcode(&c->tty, TTYC_BEL);
1.10 nicm 1009: continue;
1010: }
1011: status_message_set(c, "Bell in current window");
1.1 nicm 1012: }
1013: break;
1014: }
1015: return (1);
1016: }
1017:
1018: int
1019: server_check_window_activity(struct session *s, struct window *w)
1020: {
1.10 nicm 1021: struct client *c;
1022: u_int i;
1023:
1.1 nicm 1024: if (!(w->flags & WINDOW_ACTIVITY))
1025: return (0);
1.10 nicm 1026:
1.1 nicm 1027: if (!options_get_number(&w->options, "monitor-activity"))
1028: return (0);
1.10 nicm 1029:
1.1 nicm 1030: if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
1031: return (0);
1.10 nicm 1032: if (s->curw->window == w)
1033: return (0);
1034:
1.1 nicm 1035: session_alert_add(s, w, WINDOW_ACTIVITY);
1.10 nicm 1036: if (s->flags & SESSION_UNATTACHED)
1037: return (0);
1038: if (options_get_number(&s->options, "visual-activity")) {
1039: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1040: c = ARRAY_ITEM(&clients, i);
1041: if (c == NULL || c->session != s)
1042: continue;
1043: status_message_set(c, "Activity in window %u",
1044: winlink_find_by_window(&s->windows, w)->idx);
1045: }
1046: }
1047:
1.1 nicm 1048: return (1);
1049: }
1050:
1051: int
1052: server_check_window_content(
1053: struct session *s, struct window *w, struct window_pane *wp)
1054: {
1.10 nicm 1055: struct client *c;
1056: u_int i;
1057: char *found, *ptr;
1058:
1059: if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */
1060: return (0);
1.1 nicm 1061:
1.10 nicm 1062: ptr = options_get_string(&w->options, "monitor-content");
1063: if (ptr == NULL || *ptr == '\0')
1.1 nicm 1064: return (0);
1.10 nicm 1065:
1066: if (session_alert_has_window(s, w, WINDOW_CONTENT))
1.1 nicm 1067: return (0);
1.10 nicm 1068: if (s->curw->window == w)
1.1 nicm 1069: return (0);
1.10 nicm 1070:
1.3 nicm 1071: if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
1.1 nicm 1072: return (0);
1.10 nicm 1073: xfree(found);
1074:
1.1 nicm 1075: session_alert_add(s, w, WINDOW_CONTENT);
1.10 nicm 1076: if (s->flags & SESSION_UNATTACHED)
1077: return (0);
1078: if (options_get_number(&s->options, "visual-content")) {
1079: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1080: c = ARRAY_ITEM(&clients, i);
1081: if (c == NULL || c->session != s)
1082: continue;
1083: status_message_set(c, "Content in window %u",
1084: winlink_find_by_window(&s->windows, w)->idx);
1085: }
1086: }
1087:
1.1 nicm 1088: return (1);
1089: }
1090:
1.2 nicm 1091: /* Check if window still exists. */
1.1 nicm 1092: void
1093: server_check_window(struct window *w)
1094: {
1095: struct window_pane *wp, *wq;
1096: struct client *c;
1097: struct session *s;
1098: struct winlink *wl;
1099: u_int i, j;
1100: int destroyed, flag;
1101:
1102: flag = options_get_number(&w->options, "remain-on-exit");
1103:
1104: destroyed = 1;
1105:
1106: wp = TAILQ_FIRST(&w->panes);
1107: while (wp != NULL) {
1108: wq = TAILQ_NEXT(wp, entry);
1.2 nicm 1109: /*
1110: * If the pane has died and the remain-on-exit flag is not set,
1111: * remove the pane; otherwise, if the flag is set, don't allow
1112: * the window to be destroyed (or it'll close when the last
1113: * pane dies).
1114: */
1115: if (wp->fd == -1 && !flag) {
1.11 nicm 1116: layout_close_pane(wp);
1.1 nicm 1117: window_remove_pane(w, wp);
1118: server_redraw_window(w);
1.2 nicm 1119: } else
1120: destroyed = 0;
1.1 nicm 1121: wp = wq;
1122: }
1123:
1124: if (!destroyed)
1125: return;
1126:
1127: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1128: s = ARRAY_ITEM(&sessions, i);
1129: if (s == NULL)
1130: continue;
1131: if (!session_has(s, w))
1132: continue;
1133:
1134: restart:
1135: /* Detach window and either redraw or kill clients. */
1136: RB_FOREACH(wl, winlinks, &s->windows) {
1137: if (wl->window != w)
1138: continue;
1139: destroyed = session_detach(s, wl);
1140: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
1141: c = ARRAY_ITEM(&clients, j);
1142: if (c == NULL || c->session != s)
1143: continue;
1144: if (!destroyed) {
1145: server_redraw_client(c);
1146: continue;
1147: }
1148: c->session = NULL;
1149: server_write_client(c, MSG_EXIT, NULL, 0);
1150: }
1151: /* If the session was destroyed, bail now. */
1152: if (destroyed)
1153: break;
1154: goto restart;
1155: }
1156: }
1157:
1158: recalculate_sizes();
1159: }
1160:
1161: /* Call any once-per-second timers. */
1162: void
1163: server_second_timers(void)
1164: {
1165: struct window *w;
1166: struct window_pane *wp;
1167: u_int i;
1168: int xtimeout;
1169: struct tm now, then;
1170: static time_t last_t = 0;
1171: time_t t;
1172:
1173: t = time(NULL);
1.6 nicm 1174: xtimeout = options_get_number(&global_s_options, "lock-after-time");
1.1 nicm 1175: if (xtimeout > 0 && t > server_activity + xtimeout)
1176: server_lock();
1177:
1178: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
1179: w = ARRAY_ITEM(&windows, i);
1180: if (w == NULL)
1181: continue;
1182:
1183: TAILQ_FOREACH(wp, &w->panes, entry) {
1184: if (wp->mode != NULL && wp->mode->timer != NULL)
1185: wp->mode->timer(wp);
1186: }
1187: }
1188:
1189: /* Check for a minute having passed. */
1190: gmtime_r(&t, &now);
1191: gmtime_r(&last_t, &then);
1192: if (now.tm_min == then.tm_min)
1193: return;
1194: last_t = t;
1195:
1196: /* If locked, redraw all clients. */
1197: if (server_locked) {
1198: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1199: if (ARRAY_ITEM(&clients, i) != NULL)
1200: server_redraw_client(ARRAY_ITEM(&clients, i));
1201: }
1202: }
1203: }
1204:
1205: /* Update socket execute permissions based on whether sessions are attached. */
1206: int
1207: server_update_socket(void)
1208: {
1209: struct session *s;
1210: u_int i;
1211: static int last = -1;
1212: int n;
1213:
1214: n = 0;
1215: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1216: s = ARRAY_ITEM(&sessions, i);
1217: if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
1218: n++;
1219: break;
1220: }
1221: }
1222:
1223: if (n != last) {
1224: last = n;
1225: if (n != 0)
1226: chmod(socket_path, S_IRWXU);
1227: else
1228: chmod(socket_path, S_IRUSR|S_IWUSR);
1229: }
1230:
1231: return (n);
1232: }