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