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