Annotation of src/usr.bin/tmux/server.c, Revision 1.61
1.61 ! nicm 1: /* $OpenBSD: server.c,v 1.60 2009/10/22 19:41:51 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 {
1.60 nicm 50: int fd;
51: int events;
52:
53: void (*fn)(int, int, void *);
54: void *data;
1.45 nicm 55:
56: RB_ENTRY(poll_item) entry;
57: };
58: RB_HEAD(poll_items, poll_item) poll_items;
59:
60: int server_poll_cmp(struct poll_item *, struct poll_item *);
1.60 nicm 61: struct poll_item*server_poll_lookup(int);
62: void server_poll_add(int, int, void (*)(int, int, void *), void *);
1.45 nicm 63: struct pollfd *server_poll_flatten(int *);
1.60 nicm 64: void server_poll_dispatch(struct pollfd *, int);
1.45 nicm 65: void server_poll_reset(void);
66: RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp);
67: RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp);
68:
1.1 nicm 69: int server_create_socket(void);
1.60 nicm 70: void server_callback(int, int, void *);
1.1 nicm 71: int server_main(int);
72: void server_shutdown(void);
1.42 nicm 73: int server_should_shutdown(void);
1.1 nicm 74: void server_child_signal(void);
1.45 nicm 75: void server_fill_windows(void);
76: void server_fill_clients(void);
1.49 nicm 77: void server_fill_jobs(void);
1.31 nicm 78: void server_clean_dead(void);
1.60 nicm 79: void server_second_timers(void);
1.46 nicm 80: void server_lock_server(void);
81: void server_lock_sessions(void);
1.1 nicm 82: int server_update_socket(void);
83:
1.45 nicm 84: int
85: server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2)
86: {
1.60 nicm 87: return (pitem1->fd - pitem2->fd);
1.45 nicm 88: }
89:
1.60 nicm 90: void
91: server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data)
1.45 nicm 92: {
1.60 nicm 93: struct poll_item *pitem;
94:
95: pitem = xmalloc(sizeof *pitem);
96: pitem->fd = fd;
97: pitem->events = events;
98:
99: pitem->fn = fn;
100: pitem->data = data;
1.45 nicm 101:
1.60 nicm 102: RB_INSERT(poll_items, &poll_items, pitem);
1.45 nicm 103: }
104:
1.60 nicm 105: struct poll_item *
106: server_poll_lookup(int fd)
1.45 nicm 107: {
1.60 nicm 108: struct poll_item pitem;
1.45 nicm 109:
1.60 nicm 110: pitem.fd = fd;
111: return (RB_FIND(poll_items, &poll_items, &pitem));
1.45 nicm 112: }
113:
114: struct pollfd *
115: server_poll_flatten(int *nfds)
116: {
117: struct poll_item *pitem;
118: struct pollfd *pfds;
119:
120: pfds = NULL;
121: *nfds = 0;
122: RB_FOREACH(pitem, poll_items, &poll_items) {
123: pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds);
1.60 nicm 124: pfds[*nfds].fd = pitem->fd;
125: pfds[*nfds].events = pitem->events;
1.45 nicm 126: (*nfds)++;
127: }
128: return (pfds);
129: }
130:
131: void
1.60 nicm 132: server_poll_dispatch(struct pollfd *pfds, int nfds)
1.45 nicm 133: {
134: struct poll_item *pitem;
1.60 nicm 135: struct pollfd *pfd;
1.45 nicm 136:
1.60 nicm 137: while (nfds > 0) {
138: pfd = &pfds[--nfds];
139: if (pfd->revents != 0) {
140: pitem = server_poll_lookup(pfd->fd);
141: pitem->fn(pitem->fd, pfd->revents, pitem->data);
142: }
1.45 nicm 143: }
144: xfree(pfds);
145: }
146:
147: void
148: server_poll_reset(void)
149: {
150: struct poll_item *pitem;
151:
152: while (!RB_EMPTY(&poll_items)) {
153: pitem = RB_ROOT(&poll_items);
154: RB_REMOVE(poll_items, &poll_items, pitem);
155: xfree(pitem);
156: }
157: }
158:
1.60 nicm 159: /* Create server socket. */
160: int
161: server_create_socket(void)
1.1 nicm 162: {
1.60 nicm 163: struct sockaddr_un sa;
164: size_t size;
165: mode_t mask;
166: int fd, mode;
167:
168: memset(&sa, 0, sizeof sa);
169: sa.sun_family = AF_UNIX;
170: size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
171: if (size >= sizeof sa.sun_path) {
172: errno = ENAMETOOLONG;
173: fatal("socket failed");
174: }
175: unlink(sa.sun_path);
176:
177: if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
178: fatal("socket failed");
179:
180: mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
181: if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
182: fatal("bind failed");
183: umask(mask);
184:
185: if (listen(fd, 16) == -1)
186: fatal("listen failed");
1.1 nicm 187:
188: if ((mode = fcntl(fd, F_GETFL)) == -1)
189: fatal("fcntl failed");
190: if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
191: fatal("fcntl failed");
192: if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
193: fatal("fcntl failed");
194:
1.60 nicm 195: return (fd);
196: }
197:
198: /* Callback for server socket. */
199: void
200: server_callback(int fd, int events, unused void *data)
201: {
202: struct sockaddr_storage sa;
203: socklen_t slen = sizeof sa;
204: int newfd;
205:
206: if (events & (POLLERR|POLLNVAL|POLLHUP))
207: fatalx("lost server socket");
208: if (!(events & POLLIN))
209: return;
1.1 nicm 210:
1.60 nicm 211: newfd = accept(fd, (struct sockaddr *) &sa, &slen);
212: if (newfd == -1) {
213: if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
1.13 nicm 214: return;
1.60 nicm 215: fatal("accept failed");
216: }
217: if (sigterm) {
218: close(newfd);
219: return;
1.1 nicm 220: }
1.60 nicm 221: server_client_create(newfd);
1.1 nicm 222: }
223:
224: /* Fork new server. */
225: int
226: server_start(char *path)
227: {
1.16 nicm 228: struct client *c;
229: int pair[2], srv_fd;
230: char *cause;
231: char rpathbuf[MAXPATHLEN];
1.1 nicm 232:
233: /* The first client is special and gets a socketpair; create it. */
234: if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
235: fatal("socketpair failed");
236:
237: switch (fork()) {
238: case -1:
239: fatal("fork failed");
240: case 0:
241: break;
242: default:
243: close(pair[1]);
244: return (pair[0]);
245: }
246: close(pair[0]);
247:
248: /*
249: * Must daemonise before loading configuration as the PID changes so
250: * $TMUX would be wrong for sessions created in the config file.
251: */
1.16 nicm 252: if (daemon(1, 0) != 0)
1.1 nicm 253: fatal("daemon failed");
254:
1.16 nicm 255: logfile("server");
256: log_debug("server started, pid %ld", (long) getpid());
257:
1.1 nicm 258: ARRAY_INIT(&windows);
259: ARRAY_INIT(&clients);
1.31 nicm 260: ARRAY_INIT(&dead_clients);
1.1 nicm 261: ARRAY_INIT(&sessions);
1.31 nicm 262: ARRAY_INIT(&dead_sessions);
1.47 nicm 263: TAILQ_INIT(&session_groups);
1.15 nicm 264: mode_key_init_trees();
1.1 nicm 265: key_bindings_init();
266: utf8_build();
267:
268: start_time = time(NULL);
269: socket_path = path;
270:
1.16 nicm 271: if (realpath(socket_path, rpathbuf) == NULL)
272: strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
273: log_debug("socket path %s", socket_path);
274: setproctitle("server (%s)", rpathbuf);
275:
276: srv_fd = server_create_socket();
1.60 nicm 277: server_client_create(pair[1]);
1.16 nicm 278:
1.7 nicm 279: if (access(SYSTEM_CFG, R_OK) != 0) {
280: if (errno != ENOENT) {
1.16 nicm 281: xasprintf(
282: &cause, "%s: %s", strerror(errno), SYSTEM_CFG);
283: goto error;
284: }
1.24 nicm 285: } else if (load_cfg(SYSTEM_CFG, NULL, &cause) != 0)
1.16 nicm 286: goto error;
1.24 nicm 287: if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0)
1.16 nicm 288: goto error;
1.5 nicm 289:
1.16 nicm 290: exit(server_main(srv_fd));
1.1 nicm 291:
1.16 nicm 292: error:
293: /* Write the error and shutdown the server. */
294: c = ARRAY_FIRST(&clients);
1.1 nicm 295:
1.16 nicm 296: server_write_error(c, cause);
297: xfree(cause);
1.1 nicm 298:
1.27 nicm 299: sigterm = 1;
1.16 nicm 300: server_shutdown();
1.1 nicm 301:
302: exit(server_main(srv_fd));
303: }
304:
305: /* Main server loop. */
306: int
307: server_main(int srv_fd)
308: {
1.60 nicm 309: struct pollfd *pfds;
1.1 nicm 310: int nfds, xtimeout;
1.42 nicm 311: u_int i;
1.1 nicm 312: time_t now, last;
313:
314: siginit();
1.20 nicm 315: log_debug("server socket is %d", srv_fd);
1.1 nicm 316:
317: last = time(NULL);
318:
319: pfds = NULL;
320: for (;;) {
321: /* If sigterm, kill all windows and clients. */
322: if (sigterm)
323: server_shutdown();
324:
1.42 nicm 325: /* Stop if no sessions or clients left. */
326: if (server_should_shutdown())
327: break;
328:
1.1 nicm 329: /* Handle child exit. */
330: if (sigchld) {
1.61 ! nicm 331: sigchld = 0;
1.1 nicm 332: server_child_signal();
1.61 ! nicm 333: continue;
1.1 nicm 334: }
335:
336: /* Recreate socket on SIGUSR1. */
337: if (sigusr1) {
1.61 ! nicm 338: sigusr1 = 0;
1.1 nicm 339: close(srv_fd);
340: srv_fd = server_create_socket();
1.61 ! nicm 341: continue;
1.1 nicm 342: }
343:
1.45 nicm 344: /* Initialise pollfd array and add server socket. */
345: server_poll_reset();
1.60 nicm 346: server_poll_add(srv_fd, POLLIN, server_callback, NULL);
1.1 nicm 347:
348: /* Fill window and client sockets. */
1.49 nicm 349: server_fill_jobs();
1.45 nicm 350: server_fill_windows();
351: server_fill_clients();
1.1 nicm 352:
353: /* Update socket permissions. */
354: xtimeout = INFTIM;
1.27 nicm 355: if (server_update_socket() != 0)
1.1 nicm 356: xtimeout = POLL_TIMEOUT;
357:
358: /* Do the poll. */
1.45 nicm 359: pfds = server_poll_flatten(&nfds);
1.4 nicm 360: if (poll(pfds, nfds, xtimeout) == -1) {
1.1 nicm 361: if (errno == EAGAIN || errno == EINTR)
362: continue;
363: fatal("poll failed");
364: }
1.60 nicm 365: server_poll_dispatch(pfds, nfds);
1.1 nicm 366:
367: /* Call second-based timers. */
368: now = time(NULL);
369: if (now != last) {
370: last = now;
371: server_second_timers();
372: }
373:
1.60 nicm 374: /* Run once-per-loop events. */
375: server_job_loop();
376: server_window_loop();
377: server_client_loop();
1.1 nicm 378:
1.8 nicm 379: /* Collect any unset key bindings. */
380: key_bindings_clean();
1.31 nicm 381:
382: /* Collect dead clients and sessions. */
383: server_clean_dead();
1.1 nicm 384: }
1.45 nicm 385: server_poll_reset();
1.1 nicm 386:
387: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
388: if (ARRAY_ITEM(&sessions, i) != NULL)
389: session_destroy(ARRAY_ITEM(&sessions, i));
390: }
391: ARRAY_FREE(&sessions);
392:
393: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
394: if (ARRAY_ITEM(&clients, i) != NULL)
1.60 nicm 395: server_client_lost(ARRAY_ITEM(&clients, i));
1.1 nicm 396: }
397: ARRAY_FREE(&clients);
398:
1.15 nicm 399: mode_key_free_trees();
1.1 nicm 400: key_bindings_free();
401:
402: close(srv_fd);
403:
404: unlink(socket_path);
405: xfree(socket_path);
406:
1.6 nicm 407: options_free(&global_s_options);
408: options_free(&global_w_options);
1.1 nicm 409:
410: return (0);
411: }
412:
413: /* Kill all clients. */
414: void
415: server_shutdown(void)
416: {
417: struct session *s;
418: struct client *c;
419: u_int i, j;
420:
1.42 nicm 421: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
422: c = ARRAY_ITEM(&clients, i);
423: if (c != NULL) {
424: if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
1.60 nicm 425: server_client_lost(c);
1.42 nicm 426: else
427: server_write_client(c, MSG_SHUTDOWN, NULL, 0);
428: }
429: }
430:
1.1 nicm 431: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
432: s = ARRAY_ITEM(&sessions, i);
433: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
434: c = ARRAY_ITEM(&clients, j);
435: if (c != NULL && c->session == s) {
436: s = NULL;
437: break;
438: }
439: }
440: if (s != NULL)
441: session_destroy(s);
442: }
1.42 nicm 443: }
444:
445: /* Check if the server should be shutting down (no more clients or windows). */
446: int
447: server_should_shutdown(void)
448: {
449: u_int i;
1.1 nicm 450:
1.42 nicm 451: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
452: if (ARRAY_ITEM(&sessions, i) != NULL)
453: return (0);
454: }
1.1 nicm 455: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1.42 nicm 456: if (ARRAY_ITEM(&clients, i) != NULL)
457: return (0);
1.1 nicm 458: }
1.42 nicm 459: return (1);
1.1 nicm 460: }
461:
462: /* Handle SIGCHLD. */
463: void
464: server_child_signal(void)
465: {
466: struct window *w;
467: struct window_pane *wp;
1.53 nicm 468: struct job *job;
1.1 nicm 469: int status;
470: pid_t pid;
471: u_int i;
472:
473: for (;;) {
474: switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
475: case -1:
476: if (errno == ECHILD)
477: return;
1.39 nicm 478: fatal("waitpid failed");
1.1 nicm 479: case 0:
480: return;
481: }
1.53 nicm 482: if (!WIFSTOPPED(status)) {
483: SLIST_FOREACH(job, &all_jobs, lentry) {
484: if (pid == job->pid) {
485: job->pid = -1;
486: job->status = status;
487: }
488: }
1.1 nicm 489: continue;
1.53 nicm 490: }
1.1 nicm 491: if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
492: continue;
493:
494: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
495: w = ARRAY_ITEM(&windows, i);
496: if (w == NULL)
497: continue;
498: TAILQ_FOREACH(wp, &w->panes, entry) {
499: if (wp->pid == pid) {
500: if (killpg(pid, SIGCONT) != 0)
501: kill(pid, SIGCONT);
502: }
503: }
504: }
505: }
506: }
507:
508: /* Fill window pollfds. */
509: void
1.45 nicm 510: server_fill_windows(void)
1.1 nicm 511: {
512: struct window *w;
513: struct window_pane *wp;
514: u_int i;
1.45 nicm 515: int events;
1.1 nicm 516:
517: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
518: w = ARRAY_ITEM(&windows, i);
519: if (w == NULL)
520: continue;
521:
1.45 nicm 522: TAILQ_FOREACH(wp, &w->panes, entry) {
523: if (wp->fd == -1)
524: continue;
525: events = POLLIN;
526: if (BUFFER_USED(wp->out) > 0)
527: events |= POLLOUT;
1.60 nicm 528: server_poll_add(
529: wp->fd, events, server_window_callback, wp);
1.55 nicm 530:
531: if (wp->pipe_fd == -1)
532: continue;
533: events = 0;
534: if (BUFFER_USED(wp->pipe_buf) > 0)
535: events |= POLLOUT;
1.60 nicm 536: server_poll_add(
537: wp->pipe_fd, events, server_window_callback, wp);
1.1 nicm 538: }
1.49 nicm 539: }
1.1 nicm 540: }
541:
542: /* Fill client pollfds. */
543: void
1.45 nicm 544: server_fill_clients(void)
1.1 nicm 545: {
1.51 nicm 546: struct client *c;
547: u_int i;
548: int events;
1.1 nicm 549:
550: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
551: c = ARRAY_ITEM(&clients, i);
552:
1.45 nicm 553: if (c != NULL) {
554: events = 0;
1.16 nicm 555: if (!(c->flags & CLIENT_BAD))
1.45 nicm 556: events |= POLLIN;
1.18 nicm 557: if (c->ibuf.w.queued > 0)
1.45 nicm 558: events |= POLLOUT;
1.60 nicm 559: server_poll_add(
560: c->ibuf.fd, events, server_client_callback, c);
1.1 nicm 561: }
562:
1.45 nicm 563: if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
564: c->tty.fd != -1 && c->session != NULL) {
565: events = POLLIN;
1.1 nicm 566: if (BUFFER_USED(c->tty.out) > 0)
1.45 nicm 567: events |= POLLOUT;
1.60 nicm 568: server_poll_add(
569: c->tty.fd, events, server_client_callback, c);
1.1 nicm 570: }
571: }
572: }
573:
1.49 nicm 574: /* Fill in job fds. */
575: void
576: server_fill_jobs(void)
577: {
578: struct job *job;
579:
1.50 nicm 580: SLIST_FOREACH(job, &all_jobs, lentry) {
1.49 nicm 581: if (job->fd == -1)
582: continue;
1.60 nicm 583: server_poll_add(job->fd, POLLIN, server_job_callback, job);
1.53 nicm 584: }
585: }
586:
1.31 nicm 587: /* Free dead, unreferenced clients and sessions. */
588: void
589: server_clean_dead(void)
590: {
591: struct session *s;
592: struct client *c;
593: u_int i;
594:
595: for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
596: s = ARRAY_ITEM(&dead_sessions, i);
597: if (s == NULL || s->references != 0)
598: continue;
599: ARRAY_SET(&dead_sessions, i, NULL);
600: xfree(s);
601: }
602:
603: for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
604: c = ARRAY_ITEM(&dead_clients, i);
605: if (c == NULL || c->references != 0)
606: continue;
607: ARRAY_SET(&dead_clients, i, NULL);
608: xfree(c);
609: }
1.1 nicm 610: }
611:
1.60 nicm 612: /* Call any once-per-second timers. */
1.1 nicm 613: void
1.60 nicm 614: server_second_timers(void)
1.1 nicm 615: {
1.60 nicm 616: struct window *w;
617: struct window_pane *wp;
1.35 nicm 618: u_int i;
1.1 nicm 619:
1.60 nicm 620: if (options_get_number(&global_s_options, "lock-server"))
621: server_lock_server();
622: else
623: server_lock_sessions();
1.1 nicm 624:
1.60 nicm 625: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
626: w = ARRAY_ITEM(&windows, i);
627: if (w == NULL)
1.1 nicm 628: continue;
629:
1.60 nicm 630: TAILQ_FOREACH(wp, &w->panes, entry) {
631: if (wp->mode != NULL && wp->mode->timer != NULL)
632: wp->mode->timer(wp);
1.1 nicm 633: }
634: }
635: }
636:
1.46 nicm 637: /* Lock the server if ALL sessions have hit the time limit. */
638: void
639: server_lock_server(void)
640: {
641: struct session *s;
642: u_int i;
643: int timeout;
644: time_t t;
645:
646: t = time(NULL);
647: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
648: if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
649: continue;
650:
1.59 nicm 651: if (s->flags & SESSION_UNATTACHED) {
652: s->activity = time(NULL);
653: continue;
654: }
655:
1.46 nicm 656: timeout = options_get_number(&s->options, "lock-after-time");
657: if (timeout <= 0 || t <= s->activity + timeout)
658: return; /* not timed out */
659: }
660:
661: server_lock();
662: recalculate_sizes();
663: }
664:
665: /* Lock any sessions which have timed out. */
666: void
667: server_lock_sessions(void)
668: {
669: struct session *s;
670: u_int i;
671: int timeout;
672: time_t t;
673:
674: t = time(NULL);
675: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
676: if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
677: continue;
1.59 nicm 678:
679: if (s->flags & SESSION_UNATTACHED) {
680: s->activity = time(NULL);
681: continue;
682: }
1.46 nicm 683:
684: timeout = options_get_number(&s->options, "lock-after-time");
685: if (timeout > 0 && t > s->activity + timeout) {
686: server_lock_session(s);
687: recalculate_sizes();
1.1 nicm 688: }
689: }
690: }
691:
692: /* Update socket execute permissions based on whether sessions are attached. */
693: int
694: server_update_socket(void)
695: {
696: struct session *s;
697: u_int i;
698: static int last = -1;
699: int n;
700:
701: n = 0;
702: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
703: s = ARRAY_ITEM(&sessions, i);
704: if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
705: n++;
706: break;
707: }
708: }
709:
710: if (n != last) {
711: last = n;
712: if (n != 0)
713: chmod(socket_path, S_IRWXU);
714: else
715: chmod(socket_path, S_IRUSR|S_IWUSR);
716: }
717:
718: return (n);
719: }