Annotation of src/usr.bin/tmux/server.c, Revision 1.7
1.7 ! nicm 1: /* $OpenBSD: server.c,v 1.6 2009/07/07 19:49:19 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:
349: /*
350: * If we have no sessions and clients left, let's get out
351: * of here...
352: */
353: n = 0;
354: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
355: if (ARRAY_ITEM(&sessions, i) != NULL)
356: n++;
357: }
358: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
359: if (ARRAY_ITEM(&clients, i) != NULL)
360: n++;
361: }
362: if (n == 0)
363: break;
364: }
365: if (pfds != NULL)
366: xfree(pfds);
367:
368: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
369: if (ARRAY_ITEM(&sessions, i) != NULL)
370: session_destroy(ARRAY_ITEM(&sessions, i));
371: }
372: ARRAY_FREE(&sessions);
373:
374: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
375: if (ARRAY_ITEM(&clients, i) != NULL)
376: server_lost_client(ARRAY_ITEM(&clients, i));
377: }
378: ARRAY_FREE(&clients);
379:
380: key_bindings_free();
381:
382: close(srv_fd);
383:
384: unlink(socket_path);
385: xfree(socket_path);
386:
1.6 nicm 387: options_free(&global_s_options);
388: options_free(&global_w_options);
1.1 nicm 389: if (server_password != NULL)
390: xfree(server_password);
391:
392: return (0);
393: }
394:
395: /* Kill all clients. */
396: void
397: server_shutdown(void)
398: {
399: struct session *s;
400: struct client *c;
401: u_int i, j;
402:
403: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
404: s = ARRAY_ITEM(&sessions, i);
405: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
406: c = ARRAY_ITEM(&clients, j);
407: if (c != NULL && c->session == s) {
408: s = NULL;
409: break;
410: }
411: }
412: if (s != NULL)
413: session_destroy(s);
414: }
415:
416: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
417: c = ARRAY_ITEM(&clients, i);
418: if (c != NULL)
419: server_write_client(c, MSG_SHUTDOWN, NULL, 0);
420: }
421: }
422:
423: /* Handle SIGCHLD. */
424: void
425: server_child_signal(void)
426: {
427: struct window *w;
428: struct window_pane *wp;
429: int status;
430: pid_t pid;
431: u_int i;
432:
433: for (;;) {
434: switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
435: case -1:
436: if (errno == ECHILD)
437: return;
438: fatal("waitpid");
439: case 0:
440: return;
441: }
442: if (!WIFSTOPPED(status))
443: continue;
444: if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
445: continue;
446:
447: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
448: w = ARRAY_ITEM(&windows, i);
449: if (w == NULL)
450: continue;
451: TAILQ_FOREACH(wp, &w->panes, entry) {
452: if (wp->pid == pid) {
453: if (killpg(pid, SIGCONT) != 0)
454: kill(pid, SIGCONT);
455: }
456: }
457: }
458: }
459: }
460:
461: /* Fill window pollfds. */
462: void
463: server_fill_windows(struct pollfd **pfd)
464: {
465: struct window *w;
466: struct window_pane *wp;
467: u_int i;
468:
469: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
470: w = ARRAY_ITEM(&windows, i);
471: if (w == NULL)
472: continue;
473:
474: TAILQ_FOREACH(wp, &w->panes, entry) {
475: (*pfd)->fd = wp->fd;
476: if (wp->fd != -1) {
477: (*pfd)->events = POLLIN;
478: if (BUFFER_USED(wp->out) > 0)
479: (*pfd)->events |= POLLOUT;
480: }
481: (*pfd)++;
482: }
483: }
484: }
485:
486: /* Handle window pollfds. */
487: void
488: server_handle_windows(struct pollfd **pfd)
489: {
490: struct window *w;
491: struct window_pane *wp;
492: u_int i;
493:
494: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
495: w = ARRAY_ITEM(&windows, i);
496: if (w == NULL)
497: continue;
498:
499: TAILQ_FOREACH(wp, &w->panes, entry) {
500: if (wp->fd != -1) {
501: if (buffer_poll(*pfd, wp->in, wp->out) != 0) {
502: close(wp->fd);
503: wp->fd = -1;
504: } else
505: server_handle_window(w, wp);
506: }
507: (*pfd)++;
508: }
509:
510: server_check_window(w);
511: }
512: }
513:
514: /* Check for general redraw on client. */
515: void
516: server_check_redraw(struct client *c)
517: {
518: struct session *s;
519: struct window_pane *wp;
520: char title[512];
521: int flags, redraw;
522:
523: if (c == NULL || c->session == NULL)
524: return;
525: s = c->session;
526:
527: flags = c->tty.flags & TTY_FREEZE;
528: c->tty.flags &= ~TTY_FREEZE;
529:
530: if (options_get_number(&s->options, "set-titles")) {
531: xsnprintf(title, sizeof title, "%s:%u:%s - \"%s\"",
532: s->name, s->curw->idx, s->curw->window->name,
533: s->curw->window->active->screen->title);
534: if (c->title == NULL || strcmp(title, c->title) != 0) {
535: if (c->title != NULL)
536: xfree(c->title);
537: c->title = xstrdup(title);
538: tty_set_title(&c->tty, c->title);
539: }
540: }
541:
542: if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
543: if (c->message_string != NULL)
544: redraw = status_message_redraw(c);
545: else if (c->prompt_string != NULL)
546: redraw = status_prompt_redraw(c);
547: else
548: redraw = status_redraw(c);
549: if (!redraw)
550: c->flags &= ~CLIENT_STATUS;
551: }
552:
553: if (c->flags & CLIENT_REDRAW) {
554: if (server_locked)
555: server_redraw_locked(c);
556: else
557: screen_redraw_screen(c);
558: c->flags &= ~CLIENT_STATUS;
559: } else {
560: TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) {
561: if (wp->flags & PANE_REDRAW)
562: screen_redraw_pane(c, wp);
563: }
564: }
565:
566: if (c->flags & CLIENT_STATUS)
567: screen_redraw_status(c);
568:
569: c->tty.flags |= flags;
570:
571: c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS);
572: }
573:
574: /* Redraw client when locked. */
575: void
576: server_redraw_locked(struct client *c)
577: {
578: struct screen_write_ctx ctx;
579: struct screen screen;
580: u_int colour, xx, yy, i;
581: int style;
582:
583: xx = c->tty.sx;
584: yy = c->tty.sy - 1;
585: if (xx == 0 || yy == 0)
586: return;
1.6 nicm 587: colour = options_get_number(&global_w_options, "clock-mode-colour");
588: style = options_get_number(&global_w_options, "clock-mode-style");
1.1 nicm 589:
590: screen_init(&screen, xx, yy, 0);
591:
592: screen_write_start(&ctx, NULL, &screen);
593: clock_draw(&ctx, colour, style);
594: screen_write_stop(&ctx);
595:
596: for (i = 0; i < screen_size_y(&screen); i++)
597: tty_draw_line(&c->tty, &screen, i, 0, 0);
598: screen_redraw_status(c);
599:
600: screen_free(&screen);
601: }
602:
603: /* Check for timers on client. */
604: void
605: server_check_timers(struct client *c)
606: {
607: struct session *s;
608: struct timeval tv;
609: u_int interval;
610:
611: if (c == NULL || c->session == NULL)
612: return;
613: s = c->session;
614:
615: if (gettimeofday(&tv, NULL) != 0)
616: fatal("gettimeofday");
617:
618: if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >))
619: status_message_clear(c);
620:
621: if (c->message_string != NULL || c->prompt_string != NULL) {
622: /*
623: * Don't need timed redraw for messages/prompts so bail now.
624: * The status timer isn't reset when they are redrawn anyway.
625: */
626: return;
627: }
628: if (!options_get_number(&s->options, "status"))
629: return;
630:
631: /* Check timer; resolution is only a second so don't be too clever. */
632: interval = options_get_number(&s->options, "status-interval");
633: if (interval == 0)
634: return;
635: if (tv.tv_sec < c->status_timer.tv_sec ||
636: ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval)
637: c->flags |= CLIENT_STATUS;
638: }
639:
640: /* Fill client pollfds. */
641: void
642: server_fill_clients(struct pollfd **pfd)
643: {
644: struct client *c;
645: struct window *w;
646: struct window_pane *wp;
647: u_int i;
648:
649: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
650: c = ARRAY_ITEM(&clients, i);
651:
652: server_check_timers(c);
653: server_check_redraw(c);
654:
655: if (c == NULL)
656: (*pfd)->fd = -1;
657: else {
658: (*pfd)->fd = c->fd;
659: (*pfd)->events = POLLIN;
660: if (BUFFER_USED(c->out) > 0)
661: (*pfd)->events |= POLLOUT;
662: }
663: (*pfd)++;
664:
665: if (c == NULL || c->flags & CLIENT_SUSPENDED ||
666: c->tty.fd == -1 || c->session == NULL)
667: (*pfd)->fd = -1;
668: else {
669: (*pfd)->fd = c->tty.fd;
670: (*pfd)->events = POLLIN;
671: if (BUFFER_USED(c->tty.out) > 0)
672: (*pfd)->events |= POLLOUT;
673: }
674: (*pfd)++;
675: }
676:
677: /*
678: * Clear any window redraw flags (will have been redrawn as part of
679: * client).
680: */
681: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
682: w = ARRAY_ITEM(&windows, i);
683: if (w == NULL)
684: continue;
685:
686: w->flags &= ~WINDOW_REDRAW;
687: TAILQ_FOREACH(wp, &w->panes, entry)
688: wp->flags &= ~PANE_REDRAW;
689: }
690: }
691:
692: /* Handle client pollfds. */
693: void
694: server_handle_clients(struct pollfd **pfd)
695: {
696: struct client *c;
697: u_int i;
698:
699: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
700: c = ARRAY_ITEM(&clients, i);
701:
702: if (c != NULL) {
703: if (buffer_poll(*pfd, c->in, c->out) != 0) {
704: server_lost_client(c);
705: (*pfd) += 2;
706: continue;
707: } else
708: server_msg_dispatch(c);
709: }
710: (*pfd)++;
711:
712: if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
713: c->tty.fd != -1 && c->session != NULL) {
714: if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0)
715: server_lost_client(c);
716: else
717: server_handle_client(c);
718: }
719: (*pfd)++;
720: }
721: }
722:
723: /* accept(2) and create new client. */
724: struct client *
725: server_accept_client(int srv_fd)
726: {
727: struct sockaddr_storage sa;
728: socklen_t slen = sizeof sa;
729: int fd;
730:
731: fd = accept(srv_fd, (struct sockaddr *) &sa, &slen);
732: if (fd == -1) {
733: if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
734: return (NULL);
735: fatal("accept failed");
736: }
737: if (sigterm) {
738: close(fd);
739: return (NULL);
740: }
741: return (server_create_client(fd));
742: }
743:
744: /* Input data from client. */
745: void
746: server_handle_client(struct client *c)
747: {
748: struct window_pane *wp;
749: struct screen *s;
750: struct timeval tv;
751: struct key_binding *bd;
752: int key, prefix, status, xtimeout;
753: int mode;
754: u_char mouse[3];
755:
756: xtimeout = options_get_number(&c->session->options, "repeat-time");
757: if (xtimeout != 0 && c->flags & CLIENT_REPEAT) {
758: if (gettimeofday(&tv, NULL) != 0)
759: fatal("gettimeofday");
760: if (timercmp(&tv, &c->repeat_timer, >))
761: c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT);
762: }
763:
764: /* Process keys. */
765: prefix = options_get_number(&c->session->options, "prefix");
766: while (tty_keys_next(&c->tty, &key, mouse) == 0) {
767: server_activity = time(NULL);
768:
769: if (c->session == NULL)
770: return;
771: wp = c->session->curw->window->active; /* could die */
772:
773: status_message_clear(c);
774: if (c->prompt_string != NULL) {
775: status_prompt_key(c, key);
776: continue;
777: }
778: if (server_locked)
779: continue;
780:
781: /* Check for mouse keys. */
782: if (key == KEYC_MOUSE) {
783: window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]);
784: continue;
785: }
786:
787: /* No previous prefix key. */
788: if (!(c->flags & CLIENT_PREFIX)) {
789: if (key == prefix)
790: c->flags |= CLIENT_PREFIX;
791: else
792: window_pane_key(wp, c, key);
793: continue;
794: }
795:
796: /* Prefix key already pressed. Reset prefix and lookup key. */
797: c->flags &= ~CLIENT_PREFIX;
798: if ((bd = key_bindings_lookup(key)) == NULL) {
799: /* If repeating, treat this as a key, else ignore. */
800: if (c->flags & CLIENT_REPEAT) {
801: c->flags &= ~CLIENT_REPEAT;
802: if (key == prefix)
803: c->flags |= CLIENT_PREFIX;
804: else
805: window_pane_key(wp, c, key);
806: }
807: continue;
808: }
809:
810: /* If already repeating, but this key can't repeat, skip it. */
811: if (c->flags & CLIENT_REPEAT && !bd->can_repeat) {
812: c->flags &= ~CLIENT_REPEAT;
813: if (key == prefix)
814: c->flags |= CLIENT_PREFIX;
815: else
816: window_pane_key(wp, c, key);
817: continue;
818: }
819:
820: /* If this key can repeat, reset the repeat flags and timer. */
821: if (xtimeout != 0 && bd->can_repeat) {
822: c->flags |= CLIENT_PREFIX|CLIENT_REPEAT;
823:
824: tv.tv_sec = xtimeout / 1000;
825: tv.tv_usec = (xtimeout % 1000) * 1000L;
826: if (gettimeofday(&c->repeat_timer, NULL) != 0)
827: fatal("gettimeofday");
828: timeradd(&c->repeat_timer, &tv, &c->repeat_timer);
829: }
830:
831: /* Dispatch the command. */
832: key_bindings_dispatch(bd, c);
833: }
834: if (c->session == NULL)
835: return;
836: wp = c->session->curw->window->active; /* could die - do each loop */
837: s = wp->screen;
838:
839: /* Ensure cursor position and mode settings. */
840: status = options_get_number(&c->session->options, "status");
841: if (wp->yoff + s->cy < c->tty.sy - status)
842: tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff);
843:
844: mode = s->mode;
845: if (server_locked)
846: mode &= ~TTY_NOCURSOR;
847: tty_update_mode(&c->tty, mode);
848: }
849:
850: /* Lost a client. */
851: void
852: server_lost_client(struct client *c)
853: {
854: u_int i;
855:
856: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
857: if (ARRAY_ITEM(&clients, i) == c)
858: ARRAY_SET(&clients, i, NULL);
859: }
860:
861: tty_free(&c->tty, c->flags & CLIENT_SUSPENDED);
862:
863: screen_free(&c->status);
864:
865: if (c->title != NULL)
866: xfree(c->title);
867:
868: if (c->message_string != NULL)
869: xfree(c->message_string);
870:
871: if (c->prompt_string != NULL)
872: xfree(c->prompt_string);
873: if (c->prompt_buffer != NULL)
874: xfree(c->prompt_buffer);
875: for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++)
876: xfree(ARRAY_ITEM(&c->prompt_hdata, i));
877: ARRAY_FREE(&c->prompt_hdata);
878:
879: if (c->cwd != NULL)
880: xfree(c->cwd);
881:
882: close(c->fd);
883: buffer_destroy(c->in);
884: buffer_destroy(c->out);
885: xfree(c);
886:
887: recalculate_sizes();
888: }
889:
890: /* Handle window data. */
891: void
892: server_handle_window(struct window *w, struct window_pane *wp)
893: {
894: struct session *s;
895: u_int i;
896: int update;
897:
898: window_pane_parse(wp);
899:
900: if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0)
901: return;
902:
903: update = 0;
904: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
905: s = ARRAY_ITEM(&sessions, i);
906: if (s == NULL || !session_has(s, w))
907: continue;
908:
909: update += server_check_window_bell(s, w, wp);
910: update += server_check_window_activity(s, w);
911: update += server_check_window_content(s, w, wp);
912: }
913: if (update)
914: server_status_window(w);
915:
916: w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT);
917: }
918:
919: int
920: server_check_window_bell(
921: struct session *s, struct window *w, struct window_pane *wp)
922: {
923: struct client *c;
924: u_int i;
925: int action;
926:
927: if (!(w->flags & WINDOW_BELL))
928: return (0);
929: if (session_alert_has_window(s, w, WINDOW_BELL))
930: return (0);
931: session_alert_add(s, w, WINDOW_BELL);
932:
933: action = options_get_number(&s->options, "bell-action");
934: switch (action) {
935: case BELL_ANY:
936: if (s->flags & SESSION_UNATTACHED)
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: case BELL_CURRENT:
945: if (w->active != wp)
946: break;
947: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
948: c = ARRAY_ITEM(&clients, i);
949: if (c != NULL && c->session == s)
950: tty_putcode(&c->tty, TTYC_BEL);
951: }
952: break;
953: }
954: return (1);
955: }
956:
957: int
958: server_check_window_activity(struct session *s, struct window *w)
959: {
960: if (!(w->flags & WINDOW_ACTIVITY))
961: return (0);
962: if (!options_get_number(&w->options, "monitor-activity"))
963: return (0);
964: if (session_alert_has_window(s, w, WINDOW_ACTIVITY))
965: return (0);
966: session_alert_add(s, w, WINDOW_ACTIVITY);
967: return (1);
968: }
969:
970: int
971: server_check_window_content(
972: struct session *s, struct window *w, struct window_pane *wp)
973: {
974: char *found, *ptr;
975:
976: if (!(w->flags & WINDOW_CONTENT))
977: return (0);
978: if ((ptr = options_get_string(&w->options, "monitor-content")) == NULL)
979: return (0);
980: if (*ptr == '\0')
981: return (0);
982: if (session_alert_has_window(s, w, WINDOW_CONTENT))
983: return (0);
1.3 nicm 984: if ((found = window_pane_search(wp, ptr, NULL)) == NULL)
1.1 nicm 985: return (0);
986: session_alert_add(s, w, WINDOW_CONTENT);
987: xfree(found);
988: return (1);
989: }
990:
1.2 nicm 991: /* Check if window still exists. */
1.1 nicm 992: void
993: server_check_window(struct window *w)
994: {
995: struct window_pane *wp, *wq;
996: struct client *c;
997: struct session *s;
998: struct winlink *wl;
999: u_int i, j;
1000: int destroyed, flag;
1001:
1002: flag = options_get_number(&w->options, "remain-on-exit");
1003:
1004: destroyed = 1;
1005:
1006: wp = TAILQ_FIRST(&w->panes);
1007: while (wp != NULL) {
1008: wq = TAILQ_NEXT(wp, entry);
1.2 nicm 1009: /*
1010: * If the pane has died and the remain-on-exit flag is not set,
1011: * remove the pane; otherwise, if the flag is set, don't allow
1012: * the window to be destroyed (or it'll close when the last
1013: * pane dies).
1014: */
1015: if (wp->fd == -1 && !flag) {
1.1 nicm 1016: window_remove_pane(w, wp);
1017: server_redraw_window(w);
1018: layout_refresh(w, 0);
1.2 nicm 1019: } else
1020: destroyed = 0;
1.1 nicm 1021: wp = wq;
1022: }
1023:
1024: if (!destroyed)
1025: return;
1026:
1027: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1028: s = ARRAY_ITEM(&sessions, i);
1029: if (s == NULL)
1030: continue;
1031: if (!session_has(s, w))
1032: continue;
1033:
1034: restart:
1035: /* Detach window and either redraw or kill clients. */
1036: RB_FOREACH(wl, winlinks, &s->windows) {
1037: if (wl->window != w)
1038: continue;
1039: destroyed = session_detach(s, wl);
1040: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
1041: c = ARRAY_ITEM(&clients, j);
1042: if (c == NULL || c->session != s)
1043: continue;
1044: if (!destroyed) {
1045: server_redraw_client(c);
1046: continue;
1047: }
1048: c->session = NULL;
1049: server_write_client(c, MSG_EXIT, NULL, 0);
1050: }
1051: /* If the session was destroyed, bail now. */
1052: if (destroyed)
1053: break;
1054: goto restart;
1055: }
1056: }
1057:
1058: recalculate_sizes();
1059: }
1060:
1061: /* Call any once-per-second timers. */
1062: void
1063: server_second_timers(void)
1064: {
1065: struct window *w;
1066: struct window_pane *wp;
1067: u_int i;
1068: int xtimeout;
1069: struct tm now, then;
1070: static time_t last_t = 0;
1071: time_t t;
1072:
1073: t = time(NULL);
1.6 nicm 1074: xtimeout = options_get_number(&global_s_options, "lock-after-time");
1.1 nicm 1075: if (xtimeout > 0 && t > server_activity + xtimeout)
1076: server_lock();
1077:
1078: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
1079: w = ARRAY_ITEM(&windows, i);
1080: if (w == NULL)
1081: continue;
1082:
1083: TAILQ_FOREACH(wp, &w->panes, entry) {
1084: if (wp->mode != NULL && wp->mode->timer != NULL)
1085: wp->mode->timer(wp);
1086: }
1087: }
1088:
1089: /* Check for a minute having passed. */
1090: gmtime_r(&t, &now);
1091: gmtime_r(&last_t, &then);
1092: if (now.tm_min == then.tm_min)
1093: return;
1094: last_t = t;
1095:
1096: /* If locked, redraw all clients. */
1097: if (server_locked) {
1098: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1099: if (ARRAY_ITEM(&clients, i) != NULL)
1100: server_redraw_client(ARRAY_ITEM(&clients, i));
1101: }
1102: }
1103: }
1104:
1105: /* Update socket execute permissions based on whether sessions are attached. */
1106: int
1107: server_update_socket(void)
1108: {
1109: struct session *s;
1110: u_int i;
1111: static int last = -1;
1112: int n;
1113:
1114: n = 0;
1115: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
1116: s = ARRAY_ITEM(&sessions, i);
1117: if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
1118: n++;
1119: break;
1120: }
1121: }
1122:
1123: if (n != last) {
1124: last = n;
1125: if (n != 0)
1126: chmod(socket_path, S_IRWXU);
1127: else
1128: chmod(socket_path, S_IRUSR|S_IWUSR);
1129: }
1130:
1131: return (n);
1132: }