Annotation of src/usr.bin/tmux/server.c, Revision 1.60
1.60 ! nicm 1: /* $OpenBSD: server.c,v 1.59 2009/10/13 06:14:08 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) {
331: server_child_signal();
332: sigchld = 0;
333: }
334:
335: /* Recreate socket on SIGUSR1. */
336: if (sigusr1) {
337: close(srv_fd);
338: srv_fd = server_create_socket();
339: sigusr1 = 0;
340: }
341:
1.45 nicm 342: /* Initialise pollfd array and add server socket. */
343: server_poll_reset();
1.60 ! nicm 344: server_poll_add(srv_fd, POLLIN, server_callback, NULL);
1.1 nicm 345:
346: /* Fill window and client sockets. */
1.49 nicm 347: server_fill_jobs();
1.45 nicm 348: server_fill_windows();
349: server_fill_clients();
1.1 nicm 350:
351: /* Update socket permissions. */
352: xtimeout = INFTIM;
1.27 nicm 353: if (server_update_socket() != 0)
1.1 nicm 354: xtimeout = POLL_TIMEOUT;
355:
356: /* Do the poll. */
1.45 nicm 357: pfds = server_poll_flatten(&nfds);
1.4 nicm 358: if (poll(pfds, nfds, xtimeout) == -1) {
1.1 nicm 359: if (errno == EAGAIN || errno == EINTR)
360: continue;
361: fatal("poll failed");
362: }
1.60 ! nicm 363: server_poll_dispatch(pfds, nfds);
1.1 nicm 364:
365: /* Call second-based timers. */
366: now = time(NULL);
367: if (now != last) {
368: last = now;
369: server_second_timers();
370: }
371:
1.60 ! nicm 372: /* Run once-per-loop events. */
! 373: server_job_loop();
! 374: server_window_loop();
! 375: server_client_loop();
1.1 nicm 376:
1.8 nicm 377: /* Collect any unset key bindings. */
378: key_bindings_clean();
1.31 nicm 379:
380: /* Collect dead clients and sessions. */
381: server_clean_dead();
1.1 nicm 382: }
1.45 nicm 383: server_poll_reset();
1.1 nicm 384:
385: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
386: if (ARRAY_ITEM(&sessions, i) != NULL)
387: session_destroy(ARRAY_ITEM(&sessions, i));
388: }
389: ARRAY_FREE(&sessions);
390:
391: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
392: if (ARRAY_ITEM(&clients, i) != NULL)
1.60 ! nicm 393: server_client_lost(ARRAY_ITEM(&clients, i));
1.1 nicm 394: }
395: ARRAY_FREE(&clients);
396:
1.15 nicm 397: mode_key_free_trees();
1.1 nicm 398: key_bindings_free();
399:
400: close(srv_fd);
401:
402: unlink(socket_path);
403: xfree(socket_path);
404:
1.6 nicm 405: options_free(&global_s_options);
406: options_free(&global_w_options);
1.1 nicm 407:
408: return (0);
409: }
410:
411: /* Kill all clients. */
412: void
413: server_shutdown(void)
414: {
415: struct session *s;
416: struct client *c;
417: u_int i, j;
418:
1.42 nicm 419: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
420: c = ARRAY_ITEM(&clients, i);
421: if (c != NULL) {
422: if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
1.60 ! nicm 423: server_client_lost(c);
1.42 nicm 424: else
425: server_write_client(c, MSG_SHUTDOWN, NULL, 0);
426: }
427: }
428:
1.1 nicm 429: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
430: s = ARRAY_ITEM(&sessions, i);
431: for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
432: c = ARRAY_ITEM(&clients, j);
433: if (c != NULL && c->session == s) {
434: s = NULL;
435: break;
436: }
437: }
438: if (s != NULL)
439: session_destroy(s);
440: }
1.42 nicm 441: }
442:
443: /* Check if the server should be shutting down (no more clients or windows). */
444: int
445: server_should_shutdown(void)
446: {
447: u_int i;
1.1 nicm 448:
1.42 nicm 449: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
450: if (ARRAY_ITEM(&sessions, i) != NULL)
451: return (0);
452: }
1.1 nicm 453: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
1.42 nicm 454: if (ARRAY_ITEM(&clients, i) != NULL)
455: return (0);
1.1 nicm 456: }
1.42 nicm 457: return (1);
1.1 nicm 458: }
459:
460: /* Handle SIGCHLD. */
461: void
462: server_child_signal(void)
463: {
464: struct window *w;
465: struct window_pane *wp;
1.53 nicm 466: struct job *job;
1.1 nicm 467: int status;
468: pid_t pid;
469: u_int i;
470:
471: for (;;) {
472: switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
473: case -1:
474: if (errno == ECHILD)
475: return;
1.39 nicm 476: fatal("waitpid failed");
1.1 nicm 477: case 0:
478: return;
479: }
1.53 nicm 480: if (!WIFSTOPPED(status)) {
481: SLIST_FOREACH(job, &all_jobs, lentry) {
482: if (pid == job->pid) {
483: job->pid = -1;
484: job->status = status;
485: }
486: }
1.1 nicm 487: continue;
1.53 nicm 488: }
1.1 nicm 489: if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
490: continue;
491:
492: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
493: w = ARRAY_ITEM(&windows, i);
494: if (w == NULL)
495: continue;
496: TAILQ_FOREACH(wp, &w->panes, entry) {
497: if (wp->pid == pid) {
498: if (killpg(pid, SIGCONT) != 0)
499: kill(pid, SIGCONT);
500: }
501: }
502: }
503: }
504: }
505:
506: /* Fill window pollfds. */
507: void
1.45 nicm 508: server_fill_windows(void)
1.1 nicm 509: {
510: struct window *w;
511: struct window_pane *wp;
512: u_int i;
1.45 nicm 513: int events;
1.1 nicm 514:
515: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
516: w = ARRAY_ITEM(&windows, i);
517: if (w == NULL)
518: continue;
519:
1.45 nicm 520: TAILQ_FOREACH(wp, &w->panes, entry) {
521: if (wp->fd == -1)
522: continue;
523: events = POLLIN;
524: if (BUFFER_USED(wp->out) > 0)
525: events |= POLLOUT;
1.60 ! nicm 526: server_poll_add(
! 527: wp->fd, events, server_window_callback, wp);
1.55 nicm 528:
529: if (wp->pipe_fd == -1)
530: continue;
531: events = 0;
532: if (BUFFER_USED(wp->pipe_buf) > 0)
533: events |= POLLOUT;
1.60 ! nicm 534: server_poll_add(
! 535: wp->pipe_fd, events, server_window_callback, wp);
1.1 nicm 536: }
1.49 nicm 537: }
1.1 nicm 538: }
539:
540: /* Fill client pollfds. */
541: void
1.45 nicm 542: server_fill_clients(void)
1.1 nicm 543: {
1.51 nicm 544: struct client *c;
545: u_int i;
546: int events;
1.1 nicm 547:
548: for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
549: c = ARRAY_ITEM(&clients, i);
550:
1.45 nicm 551: if (c != NULL) {
552: events = 0;
1.16 nicm 553: if (!(c->flags & CLIENT_BAD))
1.45 nicm 554: events |= POLLIN;
1.18 nicm 555: if (c->ibuf.w.queued > 0)
1.45 nicm 556: events |= POLLOUT;
1.60 ! nicm 557: server_poll_add(
! 558: c->ibuf.fd, events, server_client_callback, c);
1.1 nicm 559: }
560:
1.45 nicm 561: if (c != NULL && !(c->flags & CLIENT_SUSPENDED) &&
562: c->tty.fd != -1 && c->session != NULL) {
563: events = POLLIN;
1.1 nicm 564: if (BUFFER_USED(c->tty.out) > 0)
1.45 nicm 565: events |= POLLOUT;
1.60 ! nicm 566: server_poll_add(
! 567: c->tty.fd, events, server_client_callback, c);
1.1 nicm 568: }
569: }
570: }
571:
1.49 nicm 572: /* Fill in job fds. */
573: void
574: server_fill_jobs(void)
575: {
576: struct job *job;
577:
1.50 nicm 578: SLIST_FOREACH(job, &all_jobs, lentry) {
1.49 nicm 579: if (job->fd == -1)
580: continue;
1.60 ! nicm 581: server_poll_add(job->fd, POLLIN, server_job_callback, job);
1.53 nicm 582: }
583: }
584:
1.31 nicm 585: /* Free dead, unreferenced clients and sessions. */
586: void
587: server_clean_dead(void)
588: {
589: struct session *s;
590: struct client *c;
591: u_int i;
592:
593: for (i = 0; i < ARRAY_LENGTH(&dead_sessions); i++) {
594: s = ARRAY_ITEM(&dead_sessions, i);
595: if (s == NULL || s->references != 0)
596: continue;
597: ARRAY_SET(&dead_sessions, i, NULL);
598: xfree(s);
599: }
600:
601: for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
602: c = ARRAY_ITEM(&dead_clients, i);
603: if (c == NULL || c->references != 0)
604: continue;
605: ARRAY_SET(&dead_clients, i, NULL);
606: xfree(c);
607: }
1.1 nicm 608: }
609:
1.60 ! nicm 610: /* Call any once-per-second timers. */
1.1 nicm 611: void
1.60 ! nicm 612: server_second_timers(void)
1.1 nicm 613: {
1.60 ! nicm 614: struct window *w;
! 615: struct window_pane *wp;
1.35 nicm 616: u_int i;
1.1 nicm 617:
1.60 ! nicm 618: if (options_get_number(&global_s_options, "lock-server"))
! 619: server_lock_server();
! 620: else
! 621: server_lock_sessions();
1.1 nicm 622:
1.60 ! nicm 623: for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
! 624: w = ARRAY_ITEM(&windows, i);
! 625: if (w == NULL)
1.1 nicm 626: continue;
627:
1.60 ! nicm 628: TAILQ_FOREACH(wp, &w->panes, entry) {
! 629: if (wp->mode != NULL && wp->mode->timer != NULL)
! 630: wp->mode->timer(wp);
1.1 nicm 631: }
632: }
633: }
634:
1.46 nicm 635: /* Lock the server if ALL sessions have hit the time limit. */
636: void
637: server_lock_server(void)
638: {
639: struct session *s;
640: u_int i;
641: int timeout;
642: time_t t;
643:
644: t = time(NULL);
645: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
646: if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
647: continue;
648:
1.59 nicm 649: if (s->flags & SESSION_UNATTACHED) {
650: s->activity = time(NULL);
651: continue;
652: }
653:
1.46 nicm 654: timeout = options_get_number(&s->options, "lock-after-time");
655: if (timeout <= 0 || t <= s->activity + timeout)
656: return; /* not timed out */
657: }
658:
659: server_lock();
660: recalculate_sizes();
661: }
662:
663: /* Lock any sessions which have timed out. */
664: void
665: server_lock_sessions(void)
666: {
667: struct session *s;
668: u_int i;
669: int timeout;
670: time_t t;
671:
672: t = time(NULL);
673: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
674: if ((s = ARRAY_ITEM(&sessions, i)) == NULL)
675: continue;
1.59 nicm 676:
677: if (s->flags & SESSION_UNATTACHED) {
678: s->activity = time(NULL);
679: continue;
680: }
1.46 nicm 681:
682: timeout = options_get_number(&s->options, "lock-after-time");
683: if (timeout > 0 && t > s->activity + timeout) {
684: server_lock_session(s);
685: recalculate_sizes();
1.1 nicm 686: }
687: }
688: }
689:
690: /* Update socket execute permissions based on whether sessions are attached. */
691: int
692: server_update_socket(void)
693: {
694: struct session *s;
695: u_int i;
696: static int last = -1;
697: int n;
698:
699: n = 0;
700: for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
701: s = ARRAY_ITEM(&sessions, i);
702: if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
703: n++;
704: break;
705: }
706: }
707:
708: if (n != last) {
709: last = n;
710: if (n != 0)
711: chmod(socket_path, S_IRWXU);
712: else
713: chmod(socket_path, S_IRUSR|S_IWUSR);
714: }
715:
716: return (n);
717: }