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