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