Annotation of src/usr.bin/tmux/server.c, Revision 1.8
1.8 ! nicm 1: /* $OpenBSD: server.c,v 1.7 2009/07/12 16:07:56 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:
1.7 nicm 174: if (access(SYSTEM_CFG, R_OK) != 0) {
175: if (errno != ENOENT) {
176: log_warn("%s", SYSTEM_CFG);
177: exit(1);
178: }
179: } else {
180: if (load_cfg(SYSTEM_CFG, &cause) != 0) {
181: log_warnx("%s", cause);
182: exit(1);
183: }
184: }
1.1 nicm 185: if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) {
186: log_warnx("%s", cause);
187: exit(1);
188: }
189: logfile("server");
1.5 nicm 190:
191: /*
192: * Close stdin/stdout/stderr. Can't let daemon() do this as they are
193: * needed until now to print configuration file errors.
194: */
195: if ((null_fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
196: dup2(null_fd, STDIN_FILENO);
197: dup2(null_fd, STDOUT_FILENO);
198: dup2(null_fd, STDERR_FILENO);
199: if (null_fd > 2)
200: close(null_fd);
201: }
1.1 nicm 202:
203: log_debug("server started, pid %ld", (long) getpid());
204: log_debug("socket path %s", socket_path);
205:
206: if (realpath(socket_path, rpathbuf) == NULL)
207: strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
208: setproctitle("server (%s)", rpathbuf);
209:
210: srv_fd = server_create_socket();
211: server_create_client(pair[1]);
212:
213: exit(server_main(srv_fd));
214: }
215:
216: /* Create server socket. */
217: int
218: server_create_socket(void)
219: {
220: struct sockaddr_un sa;
221: size_t size;
222: mode_t mask;
223: int fd, mode;
224:
225: memset(&sa, 0, sizeof sa);
226: sa.sun_family = AF_UNIX;
227: size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
228: if (size >= sizeof sa.sun_path) {
229: errno = ENAMETOOLONG;
230: fatal("socket failed");
231: }
232: unlink(sa.sun_path);
233:
234: if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
235: fatal("socket failed");
236:
237: mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
238: if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
239: fatal("bind failed");
240: umask(mask);
241:
242: if (listen(fd, 16) == -1)
243: fatal("listen failed");
244:
245: if ((mode = fcntl(fd, F_GETFL)) == -1)
246: fatal("fcntl failed");
247: if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
248: fatal("fcntl failed");
249: if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
250: fatal("fcntl failed");
251:
252: return (fd);
253: }
254:
255: /* Main server loop. */
256: int
257: server_main(int srv_fd)
258: {
259: struct window *w;
260: struct pollfd *pfds, *pfd;
261: int nfds, xtimeout;
262: u_int i, n;
263: time_t now, last;
264:
265: siginit();
266:
267: last = time(NULL);
268:
269: pfds = NULL;
270: for (;;) {
271: /* If sigterm, kill all windows and clients. */
272: if (sigterm)
273: server_shutdown();
274:
275: /* Handle child exit. */
276: if (sigchld) {
277: server_child_signal();
278: sigchld = 0;
279: }
280:
281: /* Recreate socket on SIGUSR1. */
282: if (sigusr1) {
283: close(srv_fd);
284: srv_fd = server_create_socket();
285: sigusr1 = 0;
286: }
287:
288: /* Initialise pollfd array. */
289: nfds = 1;
290: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
291: w = ARRAY_ITEM(&windows, i);
292: if (w != NULL)
293: nfds += window_count_panes(w);
294: }
295: nfds += ARRAY_LENGTH(&clients) * 2;
296: pfds = xrealloc(pfds, nfds, sizeof *pfds);
297: memset(pfds, 0, nfds * sizeof *pfds);
298: pfd = pfds;
299:
300: /* Fill server socket. */
301: pfd->fd = srv_fd;
302: pfd->events = POLLIN;
303: pfd++;
304:
305: /* Fill window and client sockets. */
306: server_fill_windows(&pfd);
307: server_fill_clients(&pfd);
308:
309: /* Update socket permissions. */
310: xtimeout = INFTIM;
311: if (sigterm || server_update_socket() != 0)
312: xtimeout = POLL_TIMEOUT;
313:
314: /* Do the poll. */
1.4 nicm 315: if (poll(pfds, nfds, xtimeout) == -1) {
1.1 nicm 316: if (errno == EAGAIN || errno == EINTR)
317: continue;
318: fatal("poll failed");
319: }
320: pfd = pfds;
321:
322: /* Handle server socket. */
323: if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
324: fatalx("lost server socket");
325: if (pfd->revents & POLLIN) {
326: server_accept_client(srv_fd);
327: continue;
328: }
329: pfd++;
330:
331: /* Call second-based timers. */
332: now = time(NULL);
333: if (now != last) {
334: last = now;
335: server_second_timers();
336: }
337:
338: /* Set window names. */
339: set_window_names();
340:
341: /*
342: * Handle window and client sockets. Clients can create
343: * windows, so windows must come first to avoid messing up by
344: * increasing the array size.
345: */
346: server_handle_windows(&pfd);
347: server_handle_clients(&pfd);
348:
1.8 ! nicm 349: /* Collect any unset key bindings. */
! 350: key_bindings_clean();
! 351:
1.1 nicm 352: /*
353: * If we have no sessions and clients left, let's get out
354: * of here...
355: */
356: n = 0;
357: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
358: if (ARRAY_ITEM(&sessions, i) != NULL)
359: n++;
360: }
361: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
362: if (ARRAY_ITEM(&clients, i) != NULL)
363: n++;
364: }
365: if (n == 0)
366: break;
367: }
368: if (pfds != NULL)
369: xfree(pfds);
370:
371: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
372: if (ARRAY_ITEM(&sessions, i) != NULL)
373: session_destroy(ARRAY_ITEM(&sessions, i));
374: }
375: ARRAY_FREE(&sessions);
376:
377: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
378: if (ARRAY_ITEM(&clients, i) != NULL)
379: server_lost_client(ARRAY_ITEM(&clients, i));
380: }
381: ARRAY_FREE(&clients);
382:
383: key_bindings_free();
384:
385: close(srv_fd);
386:
387: unlink(socket_path);
388: xfree(socket_path);
389:
1.6 nicm 390: options_free(&global_s_options);
391: options_free(&global_w_options);
1.1 nicm 392: if (server_password != NULL)
393: xfree(server_password);
394:
395: return (0);
396: }
397:
398: /* Kill all clients. */
399: void
400: server_shutdown(void)
401: {
402: struct session *s;
403: struct client *c;
404: u_int i, j;
405:
406: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
407: s = ARRAY_ITEM(&sessions, i);
408: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
409: c = ARRAY_ITEM(&clients, j);
410: if (c != NULL && c->session == s) {
411: s = NULL;
412: break;
413: }
414: }
415: if (s != NULL)
416: session_destroy(s);
417: }
418:
419: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
420: c = ARRAY_ITEM(&clients, i);
421: if (c != NULL)
422: server_write_client(c, MSG_SHUTDOWN, NULL, 0);
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
560: screen_redraw_screen(c);
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)
570: screen_redraw_status(c);
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;
583: u_int colour, xx, yy, i;
584: int style;
585:
586: xx = c->tty.sx;
587: yy = c->tty.sy - 1;
588: if (xx == 0 || yy == 0)
589: return;
1.6 nicm 590: colour = options_get_number(&global_w_options, "clock-mode-colour");
591: style = options_get_number(&global_w_options, "clock-mode-style");
1.1 nicm 592:
593: screen_init(&screen, xx, yy, 0);
594:
595: screen_write_start(&ctx, NULL, &screen);
596: clock_draw(&ctx, colour, style);
597: screen_write_stop(&ctx);
598:
599: for (i = 0; i < screen_size_y(&screen); i++)
600: tty_draw_line(&c->tty, &screen, i, 0, 0);
601: screen_redraw_status(c);
602:
603: screen_free(&screen);
604: }
605:
606: /* Check for timers on client. */
607: void
608: server_check_timers(struct client *c)
609: {
610: struct session *s;
611: struct timeval tv;
612: u_int interval;
613:
614: if (c == NULL || c->session == NULL)
615: return;
616: s = c->session;
617:
618: if (gettimeofday(&tv, NULL) != 0)
619: fatal("gettimeofday");
620:
621: if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >))
622: status_message_clear(c);
623:
624: if (c->message_string != NULL || c->prompt_string != NULL) {
625: /*
626: * Don't need timed redraw for messages/prompts so bail now.
627: * The status timer isn't reset when they are redrawn anyway.
628: */
629: return;
630: }
631: if (!options_get_number(&s->options, "status"))
632: return;
633:
634: /* Check timer; resolution is only a second so don't be too clever. */
635: interval = options_get_number(&s->options, "status-interval");
636: if (interval == 0)
637: return;
638: if (tv.tv_sec < c->status_timer.tv_sec ||
639: ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval)
640: c->flags |= CLIENT_STATUS;
641: }
642:
643: /* Fill client pollfds. */
644: void
645: server_fill_clients(struct pollfd **pfd)
646: {
647: struct client *c;
648: struct window *w;
649: struct window_pane *wp;
650: u_int i;
651:
652: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
653: c = ARRAY_ITEM(&clients, i);
654:
655: server_check_timers(c);
656: server_check_redraw(c);
657:
658: if (c == NULL)
659: (*pfd)->fd = -1;
660: else {
661: (*pfd)->fd = c->fd;
662: (*pfd)->events = POLLIN;
663: if (BUFFER_USED(c->out) > 0)
664: (*pfd)->events |= POLLOUT;
665: }
666: (*pfd)++;
667:
668: if (c == NULL || c->flags & CLIENT_SUSPENDED ||
669: c->tty.fd == -1 || c->session == NULL)
670: (*pfd)->fd = -1;
671: else {
672: (*pfd)->fd = c->tty.fd;
673: (*pfd)->events = POLLIN;
674: if (BUFFER_USED(c->tty.out) > 0)
675: (*pfd)->events |= POLLOUT;
676: }
677: (*pfd)++;
678: }
679:
680: /*
681: * Clear any window redraw flags (will have been redrawn as part of
682: * client).
683: */
684: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
685: w = ARRAY_ITEM(&windows, i);
686: if (w == NULL)
687: continue;
688:
689: w->flags &= ~WINDOW_REDRAW;
690: TAILQ_FOREACH(wp, &w->panes, entry)
691: wp->flags &= ~PANE_REDRAW;
692: }
693: }
694:
695: /* Handle client pollfds. */
696: void
697: server_handle_clients(struct pollfd **pfd)
698: {
699: struct client *c;
700: u_int i;
701:
702: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
703: c = ARRAY_ITEM(&clients, i);
704:
705: if (c != NULL) {
706: if (buffer_poll(*pfd, c->in, c->out) != 0) {
707: server_lost_client(c);
708: (*pfd) += 2;
709: continue;
710: } else
711: server_msg_dispatch(c);
712: }
713: (*pfd)++;
714:
715: if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
716: c->tty.fd != -1 && c->session != NULL) {
717: if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0)
718: server_lost_client(c);
719: else
720: server_handle_client(c);
721: }
722: (*pfd)++;
723: }
724: }
725:
726: /* accept(2) and create new client. */
727: struct client *
728: server_accept_client(int srv_fd)
729: {
730: struct sockaddr_storage sa;
731: socklen_t slen = sizeof sa;
732: int fd;
733:
734: fd = accept(srv_fd, (struct sockaddr *) &sa, &slen);
735: if (fd == -1) {
736: if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
737: return (NULL);
738: fatal("accept failed");
739: }
740: if (sigterm) {
741: close(fd);
742: return (NULL);
743: }
744: return (server_create_client(fd));
745: }
746:
747: /* Input data from client. */
748: void
749: server_handle_client(struct client *c)
750: {
751: struct window_pane *wp;
752: struct screen *s;
753: struct timeval tv;
754: struct key_binding *bd;
755: int key, prefix, status, xtimeout;
756: int mode;
757: u_char mouse[3];
758:
759: xtimeout = options_get_number(&c->session->options, "repeat-time");
760: if (xtimeout != 0 && c->flags & CLIENT_REPEAT) {
761: if (gettimeofday(&tv, NULL) != 0)
762: fatal("gettimeofday");
763: if (timercmp(&tv, &c->repeat_timer, >))
764: c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
765: }
766:
767: /* Process keys. */
768: prefix = options_get_number(&c->session->options, "prefix");
769: while (tty_keys_next(&c->tty, &key, mouse) == 0) {
770: server_activity = time(NULL);
771:
772: if (c->session == NULL)
773: return;
774: wp = c->session->curw->window->active; /* could die */
775:
776: status_message_clear(c);
777: if (c->prompt_string != NULL) {
778: status_prompt_key(c, key);
779: continue;
780: }
781: if (server_locked)
782: continue;
783:
784: /* Check for mouse keys. */
785: if (key == KEYC_MOUSE) {
786: window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]);
787: continue;
788: }
789:
790: /* No previous prefix key. */
791: if (!(c->flags & CLIENT_PREFIX)) {
792: if (key == prefix)
793: c->flags |= CLIENT_PREFIX;
794: else
795: window_pane_key(wp, c, key);
796: continue;
797: }
798:
799: /* Prefix key already pressed. Reset prefix and lookup key. */
800: c->flags &= ~CLIENT_PREFIX;
801: if ((bd = key_bindings_lookup(key)) == NULL) {
802: /* If repeating, treat this as a key, else ignore. */
803: if (c->flags & CLIENT_REPEAT) {
804: c->flags &= ~CLIENT_REPEAT;
805: if (key == prefix)
806: c->flags |= CLIENT_PREFIX;
807: else
808: window_pane_key(wp, c, key);
809: }
810: continue;
811: }
812:
813: /* If already repeating, but this key can't repeat, skip it. */
814: if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
815: c->flags &= ~CLIENT_REPEAT;
816: if (key == prefix)
817: c->flags |= CLIENT_PREFIX;
818: else
819: window_pane_key(wp, c, key);
820: continue;
821: }
822:
823: /* If this key can repeat, reset the repeat flags and timer. */
824: if (xtimeout != 0 && bd->can_repeat) {
825: c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
826:
827: tv.tv_sec = xtimeout / 1000;
828: tv.tv_usec = (xtimeout % 1000) * 1000L;
829: if (gettimeofday(&c->repeat_timer, NULL) != 0)
830: fatal("gettimeofday");
831: timeradd(&c->repeat_timer, &tv, &c->repeat_timer);
832: }
833:
834: /* Dispatch the command. */
835: key_bindings_dispatch(bd, c);
836: }
837: if (c->session == NULL)
838: return;
839: wp = c->session->curw->window->active; /* could die - do each loop */
840: s = wp->screen;
841:
842: /* Ensure cursor position and mode settings. */
843: status = options_get_number(&c->session->options, "status");
844: if (wp->yoff + s->cy < c->tty.sy - status)
845: tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff);
846:
847: mode = s->mode;
848: if (server_locked)
849: mode &= ~TTY_NOCURSOR;
850: tty_update_mode(&c->tty, mode);
851: }
852:
853: /* Lost a client. */
854: void
855: server_lost_client(struct client *c)
856: {
857: u_int i;
858:
859: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
860: if (ARRAY_ITEM(&clients, i) == c)
861: ARRAY_SET(&clients, i, NULL);
862: }
863:
864: tty_free(&c->tty, c->flags & CLIENT_SUSPENDED);
865:
866: screen_free(&c->status);
867:
868: if (c->title != NULL)
869: xfree(c->title);
870:
871: if (c->message_string != NULL)
872: xfree(c->message_string);
873:
874: if (c->prompt_string != NULL)
875: xfree(c->prompt_string);
876: if (c->prompt_buffer != NULL)
877: xfree(c->prompt_buffer);
878: for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
879: xfree(ARRAY_ITEM(&c->prompt_hdata, i));
880: ARRAY_FREE(&c->prompt_hdata);
881:
882: if (c->cwd != NULL)
883: xfree(c->cwd);
884:
885: close(c->fd);
886: buffer_destroy(c->in);
887: buffer_destroy(c->out);
888: xfree(c);
889:
890: recalculate_sizes();
891: }
892:
893: /* Handle window data. */
894: void
895: server_handle_window(struct window *w, struct window_pane *wp)
896: {
897: struct session *s;
898: u_int i;
899: int update;
900:
901: window_pane_parse(wp);
902:
903: if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0)
904: return;
905:
906: update = 0;
907: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
908: s = ARRAY_ITEM(&sessions, i);
909: if (s == NULL || !session_has(s, w))
910: continue;
911:
912: update += server_check_window_bell(s, w, wp);
913: update += server_check_window_activity(s, w);
914: update += server_check_window_content(s, w, wp);
915: }
916: if (update)
917: server_status_window(w);
918:
919: w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
920: }
921:
922: int
923: server_check_window_bell(
924: struct session *s, struct window *w, struct window_pane *wp)
925: {
926: struct client *c;
927: u_int i;
928: int action;
929:
930: if (!(w->flags & WINDOW_BELL))
931: return (0);
932: if (session_alert_has_window(s, w, WINDOW_BELL))
933: return (0);
934: session_alert_add(s, w, WINDOW_BELL);
935:
936: action = options_get_number(&s->options, "bell-action");
937: switch (action) {
938: case BELL_ANY:
939: if (s->flags & SESSION_UNATTACHED)
940: break;
941: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
942: c = ARRAY_ITEM(&clients, i);
943: if (c != NULL && c->session == s)
944: tty_putcode(&c->tty, TTYC_BEL);
945: }
946: break;
947: case BELL_CURRENT:
948: if (w->active != wp)
949: break;
950: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
951: c = ARRAY_ITEM(&clients, i);
952: if (c != NULL && c->session == s)
953: tty_putcode(&c->tty, TTYC_BEL);
954: }
955: break;
956: }
957: return (1);
958: }
959:
960: int
961: server_check_window_activity(struct session *s, struct window *w)
962: {
963: if (!(w->flags & WINDOW_ACTIVITY))
964: return (0);
965: if (!options_get_number(&w->options, "monitor-activity"))
966: return (0);
967: if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
968: return (0);
969: session_alert_add(s, w, WINDOW_ACTIVITY);
970: return (1);
971: }
972:
973: int
974: server_check_window_content(
975: struct session *s, struct window *w, struct window_pane *wp)
976: {
977: char *found, *ptr;
978:
979: if (!(w->flags & WINDOW_CONTENT))
980: return (0);
981: if ((ptr = options_get_string(&w->options, "monitor-content")) == NULL)
982: return (0);
983: if (*ptr == '\0')
984: return (0);
985: if (session_alert_has_window(s, w, WINDOW_CONTENT))
986: return (0);
1.3 nicm 987: if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
1.1 nicm 988: return (0);
989: session_alert_add(s, w, WINDOW_CONTENT);
990: xfree(found);
991: return (1);
992: }
993:
1.2 nicm 994: /* Check if window still exists. */
1.1 nicm 995: void
996: server_check_window(struct window *w)
997: {
998: struct window_pane *wp, *wq;
999: struct client *c;
1000: struct session *s;
1001: struct winlink *wl;
1002: u_int i, j;
1003: int destroyed, flag;
1004:
1005: flag = options_get_number(&w->options, "remain-on-exit");
1006:
1007: destroyed = 1;
1008:
1009: wp = TAILQ_FIRST(&w->panes);
1010: while (wp != NULL) {
1011: wq = TAILQ_NEXT(wp, entry);
1.2 nicm 1012: /*
1013: * If the pane has died and the remain-on-exit flag is not set,
1014: * remove the pane; otherwise, if the flag is set, don't allow
1015: * the window to be destroyed (or it'll close when the last
1016: * pane dies).
1017: */
1018: if (wp->fd == -1 && !flag) {
1.1 nicm 1019: window_remove_pane(w, wp);
1020: server_redraw_window(w);
1021: layout_refresh(w, 0);
1.2 nicm 1022: } else
1023: destroyed = 0;
1.1 nicm 1024: wp = wq;
1025: }
1026:
1027: if (!destroyed)
1028: return;
1029:
1030: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1031: s = ARRAY_ITEM(&sessions, i);
1032: if (s == NULL)
1033: continue;
1034: if (!session_has(s, w))
1035: continue;
1036:
1037: restart:
1038: /* Detach window and either redraw or kill clients. */
1039: RB_FOREACH(wl, winlinks, &s->windows) {
1040: if (wl->window != w)
1041: continue;
1042: destroyed = session_detach(s, wl);
1043: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
1044: c = ARRAY_ITEM(&clients, j);
1045: if (c == NULL || c->session != s)
1046: continue;
1047: if (!destroyed) {
1048: server_redraw_client(c);
1049: continue;
1050: }
1051: c->session = NULL;
1052: server_write_client(c, MSG_EXIT, NULL, 0);
1053: }
1054: /* If the session was destroyed, bail now. */
1055: if (destroyed)
1056: break;
1057: goto restart;
1058: }
1059: }
1060:
1061: recalculate_sizes();
1062: }
1063:
1064: /* Call any once-per-second timers. */
1065: void
1066: server_second_timers(void)
1067: {
1068: struct window *w;
1069: struct window_pane *wp;
1070: u_int i;
1071: int xtimeout;
1072: struct tm now, then;
1073: static time_t last_t = 0;
1074: time_t t;
1075:
1076: t = time(NULL);
1.6 nicm 1077: xtimeout = options_get_number(&global_s_options, "lock-after-time");
1.1 nicm 1078: if (xtimeout > 0 && t > server_activity + xtimeout)
1079: server_lock();
1080:
1081: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
1082: w = ARRAY_ITEM(&windows, i);
1083: if (w == NULL)
1084: continue;
1085:
1086: TAILQ_FOREACH(wp, &w->panes, entry) {
1087: if (wp->mode != NULL && wp->mode->timer != NULL)
1088: wp->mode->timer(wp);
1089: }
1090: }
1091:
1092: /* Check for a minute having passed. */
1093: gmtime_r(&t, &now);
1094: gmtime_r(&last_t, &then);
1095: if (now.tm_min == then.tm_min)
1096: return;
1097: last_t = t;
1098:
1099: /* If locked, redraw all clients. */
1100: if (server_locked) {
1101: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1102: if (ARRAY_ITEM(&clients, i) != NULL)
1103: server_redraw_client(ARRAY_ITEM(&clients, i));
1104: }
1105: }
1106: }
1107:
1108: /* Update socket execute permissions based on whether sessions are attached. */
1109: int
1110: server_update_socket(void)
1111: {
1112: struct session *s;
1113: u_int i;
1114: static int last = -1;
1115: int n;
1116:
1117: n = 0;
1118: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1119: s = ARRAY_ITEM(&sessions, i);
1120: if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
1121: n++;
1122: break;
1123: }
1124: }
1125:
1126: if (n != last) {
1127: last = n;
1128: if (n != 0)
1129: chmod(socket_path, S_IRWXU);
1130: else
1131: chmod(socket_path, S_IRUSR|S_IWUSR);
1132: }
1133:
1134: return (n);
1135: }