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