1*311827fbSnicm /* $OpenBSD: server.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */ 2*311827fbSnicm 3*311827fbSnicm /* 4*311827fbSnicm * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 5*311827fbSnicm * 6*311827fbSnicm * Permission to use, copy, modify, and distribute this software for any 7*311827fbSnicm * purpose with or without fee is hereby granted, provided that the above 8*311827fbSnicm * copyright notice and this permission notice appear in all copies. 9*311827fbSnicm * 10*311827fbSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*311827fbSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*311827fbSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*311827fbSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*311827fbSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15*311827fbSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16*311827fbSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*311827fbSnicm */ 18*311827fbSnicm 19*311827fbSnicm #include <sys/types.h> 20*311827fbSnicm #include <sys/ioctl.h> 21*311827fbSnicm #include <sys/socket.h> 22*311827fbSnicm #include <sys/stat.h> 23*311827fbSnicm #include <sys/un.h> 24*311827fbSnicm #include <sys/wait.h> 25*311827fbSnicm 26*311827fbSnicm #include <errno.h> 27*311827fbSnicm #include <fcntl.h> 28*311827fbSnicm #include <signal.h> 29*311827fbSnicm #include <stdio.h> 30*311827fbSnicm #include <stdlib.h> 31*311827fbSnicm #include <string.h> 32*311827fbSnicm #include <syslog.h> 33*311827fbSnicm #include <termios.h> 34*311827fbSnicm #include <time.h> 35*311827fbSnicm #include <unistd.h> 36*311827fbSnicm 37*311827fbSnicm #include "tmux.h" 38*311827fbSnicm 39*311827fbSnicm /* 40*311827fbSnicm * Main server functions. 41*311827fbSnicm */ 42*311827fbSnicm 43*311827fbSnicm /* Client list. */ 44*311827fbSnicm struct clients clients; 45*311827fbSnicm 46*311827fbSnicm int server_create_socket(void); 47*311827fbSnicm int server_main(int); 48*311827fbSnicm void server_shutdown(void); 49*311827fbSnicm void server_child_signal(void); 50*311827fbSnicm void server_fill_windows(struct pollfd **); 51*311827fbSnicm void server_handle_windows(struct pollfd **); 52*311827fbSnicm void server_fill_clients(struct pollfd **); 53*311827fbSnicm void server_handle_clients(struct pollfd **); 54*311827fbSnicm struct client *server_accept_client(int); 55*311827fbSnicm void server_handle_client(struct client *); 56*311827fbSnicm void server_handle_window(struct window *, struct window_pane *); 57*311827fbSnicm int server_check_window_bell(struct session *, struct window *, 58*311827fbSnicm struct window_pane *); 59*311827fbSnicm int server_check_window_activity(struct session *, 60*311827fbSnicm struct window *); 61*311827fbSnicm int server_check_window_content(struct session *, struct window *, 62*311827fbSnicm struct window_pane *); 63*311827fbSnicm void server_lost_client(struct client *); 64*311827fbSnicm void server_check_window(struct window *); 65*311827fbSnicm void server_check_redraw(struct client *); 66*311827fbSnicm void server_redraw_locked(struct client *); 67*311827fbSnicm void server_check_timers(struct client *); 68*311827fbSnicm void server_second_timers(void); 69*311827fbSnicm int server_update_socket(void); 70*311827fbSnicm 71*311827fbSnicm /* Create a new client. */ 72*311827fbSnicm struct client * 73*311827fbSnicm server_create_client(int fd) 74*311827fbSnicm { 75*311827fbSnicm struct client *c; 76*311827fbSnicm int mode; 77*311827fbSnicm u_int i; 78*311827fbSnicm 79*311827fbSnicm if ((mode = fcntl(fd, F_GETFL)) == -1) 80*311827fbSnicm fatal("fcntl failed"); 81*311827fbSnicm if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) 82*311827fbSnicm fatal("fcntl failed"); 83*311827fbSnicm if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 84*311827fbSnicm fatal("fcntl failed"); 85*311827fbSnicm 86*311827fbSnicm c = xcalloc(1, sizeof *c); 87*311827fbSnicm c->fd = fd; 88*311827fbSnicm c->in = buffer_create(BUFSIZ); 89*311827fbSnicm c->out = buffer_create(BUFSIZ); 90*311827fbSnicm 91*311827fbSnicm ARRAY_INIT(&c->prompt_hdata); 92*311827fbSnicm 93*311827fbSnicm c->tty.fd = -1; 94*311827fbSnicm c->title = NULL; 95*311827fbSnicm 96*311827fbSnicm c->session = NULL; 97*311827fbSnicm c->tty.sx = 80; 98*311827fbSnicm c->tty.sy = 25; 99*311827fbSnicm screen_init(&c->status, c->tty.sx, 1, 0); 100*311827fbSnicm 101*311827fbSnicm c->message_string = NULL; 102*311827fbSnicm 103*311827fbSnicm c->prompt_string = NULL; 104*311827fbSnicm c->prompt_buffer = NULL; 105*311827fbSnicm c->prompt_index = 0; 106*311827fbSnicm 107*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 108*311827fbSnicm if (ARRAY_ITEM(&clients, i) == NULL) { 109*311827fbSnicm ARRAY_SET(&clients, i, c); 110*311827fbSnicm return (c); 111*311827fbSnicm } 112*311827fbSnicm } 113*311827fbSnicm ARRAY_ADD(&clients, c); 114*311827fbSnicm return (c); 115*311827fbSnicm } 116*311827fbSnicm 117*311827fbSnicm /* Find client index. */ 118*311827fbSnicm int 119*311827fbSnicm server_client_index(struct client *c) 120*311827fbSnicm { 121*311827fbSnicm u_int i; 122*311827fbSnicm 123*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 124*311827fbSnicm if (c == ARRAY_ITEM(&clients, i)) 125*311827fbSnicm return (i); 126*311827fbSnicm } 127*311827fbSnicm return (-1); 128*311827fbSnicm } 129*311827fbSnicm 130*311827fbSnicm /* Fork new server. */ 131*311827fbSnicm int 132*311827fbSnicm server_start(char *path) 133*311827fbSnicm { 134*311827fbSnicm int pair[2], srv_fd; 135*311827fbSnicm char *cause; 136*311827fbSnicm char rpathbuf[MAXPATHLEN]; 137*311827fbSnicm 138*311827fbSnicm /* The first client is special and gets a socketpair; create it. */ 139*311827fbSnicm if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) 140*311827fbSnicm fatal("socketpair failed"); 141*311827fbSnicm 142*311827fbSnicm switch (fork()) { 143*311827fbSnicm case -1: 144*311827fbSnicm fatal("fork failed"); 145*311827fbSnicm case 0: 146*311827fbSnicm break; 147*311827fbSnicm default: 148*311827fbSnicm close(pair[1]); 149*311827fbSnicm return (pair[0]); 150*311827fbSnicm } 151*311827fbSnicm close(pair[0]); 152*311827fbSnicm 153*311827fbSnicm /* 154*311827fbSnicm * Must daemonise before loading configuration as the PID changes so 155*311827fbSnicm * $TMUX would be wrong for sessions created in the config file. 156*311827fbSnicm */ 157*311827fbSnicm if (daemon(1, 1) != 0) 158*311827fbSnicm fatal("daemon failed"); 159*311827fbSnicm 160*311827fbSnicm ARRAY_INIT(&windows); 161*311827fbSnicm ARRAY_INIT(&clients); 162*311827fbSnicm ARRAY_INIT(&sessions); 163*311827fbSnicm key_bindings_init(); 164*311827fbSnicm utf8_build(); 165*311827fbSnicm 166*311827fbSnicm server_locked = 0; 167*311827fbSnicm server_password = NULL; 168*311827fbSnicm server_activity = time(NULL); 169*311827fbSnicm 170*311827fbSnicm start_time = time(NULL); 171*311827fbSnicm socket_path = path; 172*311827fbSnicm 173*311827fbSnicm if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) { 174*311827fbSnicm log_warnx("%s", cause); 175*311827fbSnicm exit(1); 176*311827fbSnicm } 177*311827fbSnicm logfile("server"); 178*311827fbSnicm 179*311827fbSnicm log_debug("server started, pid %ld", (long) getpid()); 180*311827fbSnicm log_debug("socket path %s", socket_path); 181*311827fbSnicm 182*311827fbSnicm if (realpath(socket_path, rpathbuf) == NULL) 183*311827fbSnicm strlcpy(rpathbuf, socket_path, sizeof rpathbuf); 184*311827fbSnicm setproctitle("server (%s)", rpathbuf); 185*311827fbSnicm 186*311827fbSnicm srv_fd = server_create_socket(); 187*311827fbSnicm server_create_client(pair[1]); 188*311827fbSnicm 189*311827fbSnicm exit(server_main(srv_fd)); 190*311827fbSnicm } 191*311827fbSnicm 192*311827fbSnicm /* Create server socket. */ 193*311827fbSnicm int 194*311827fbSnicm server_create_socket(void) 195*311827fbSnicm { 196*311827fbSnicm struct sockaddr_un sa; 197*311827fbSnicm size_t size; 198*311827fbSnicm mode_t mask; 199*311827fbSnicm int fd, mode; 200*311827fbSnicm 201*311827fbSnicm memset(&sa, 0, sizeof sa); 202*311827fbSnicm sa.sun_family = AF_UNIX; 203*311827fbSnicm size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); 204*311827fbSnicm if (size >= sizeof sa.sun_path) { 205*311827fbSnicm errno = ENAMETOOLONG; 206*311827fbSnicm fatal("socket failed"); 207*311827fbSnicm } 208*311827fbSnicm unlink(sa.sun_path); 209*311827fbSnicm 210*311827fbSnicm if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 211*311827fbSnicm fatal("socket failed"); 212*311827fbSnicm 213*311827fbSnicm mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); 214*311827fbSnicm if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) 215*311827fbSnicm fatal("bind failed"); 216*311827fbSnicm umask(mask); 217*311827fbSnicm 218*311827fbSnicm if (listen(fd, 16) == -1) 219*311827fbSnicm fatal("listen failed"); 220*311827fbSnicm 221*311827fbSnicm if ((mode = fcntl(fd, F_GETFL)) == -1) 222*311827fbSnicm fatal("fcntl failed"); 223*311827fbSnicm if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) 224*311827fbSnicm fatal("fcntl failed"); 225*311827fbSnicm if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) 226*311827fbSnicm fatal("fcntl failed"); 227*311827fbSnicm 228*311827fbSnicm return (fd); 229*311827fbSnicm } 230*311827fbSnicm 231*311827fbSnicm /* Main server loop. */ 232*311827fbSnicm int 233*311827fbSnicm server_main(int srv_fd) 234*311827fbSnicm { 235*311827fbSnicm struct window *w; 236*311827fbSnicm struct pollfd *pfds, *pfd; 237*311827fbSnicm int nfds, xtimeout; 238*311827fbSnicm u_int i, n; 239*311827fbSnicm time_t now, last; 240*311827fbSnicm 241*311827fbSnicm siginit(); 242*311827fbSnicm 243*311827fbSnicm last = time(NULL); 244*311827fbSnicm 245*311827fbSnicm pfds = NULL; 246*311827fbSnicm for (;;) { 247*311827fbSnicm /* If sigterm, kill all windows and clients. */ 248*311827fbSnicm if (sigterm) 249*311827fbSnicm server_shutdown(); 250*311827fbSnicm 251*311827fbSnicm /* Handle child exit. */ 252*311827fbSnicm if (sigchld) { 253*311827fbSnicm server_child_signal(); 254*311827fbSnicm sigchld = 0; 255*311827fbSnicm } 256*311827fbSnicm 257*311827fbSnicm /* Recreate socket on SIGUSR1. */ 258*311827fbSnicm if (sigusr1) { 259*311827fbSnicm close(srv_fd); 260*311827fbSnicm srv_fd = server_create_socket(); 261*311827fbSnicm sigusr1 = 0; 262*311827fbSnicm } 263*311827fbSnicm 264*311827fbSnicm /* Initialise pollfd array. */ 265*311827fbSnicm nfds = 1; 266*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 267*311827fbSnicm w = ARRAY_ITEM(&windows, i); 268*311827fbSnicm if (w != NULL) 269*311827fbSnicm nfds += window_count_panes(w); 270*311827fbSnicm } 271*311827fbSnicm nfds += ARRAY_LENGTH(&clients) * 2; 272*311827fbSnicm pfds = xrealloc(pfds, nfds, sizeof *pfds); 273*311827fbSnicm memset(pfds, 0, nfds * sizeof *pfds); 274*311827fbSnicm pfd = pfds; 275*311827fbSnicm 276*311827fbSnicm /* Fill server socket. */ 277*311827fbSnicm pfd->fd = srv_fd; 278*311827fbSnicm pfd->events = POLLIN; 279*311827fbSnicm pfd++; 280*311827fbSnicm 281*311827fbSnicm /* Fill window and client sockets. */ 282*311827fbSnicm server_fill_windows(&pfd); 283*311827fbSnicm server_fill_clients(&pfd); 284*311827fbSnicm 285*311827fbSnicm /* Update socket permissions. */ 286*311827fbSnicm xtimeout = INFTIM; 287*311827fbSnicm if (sigterm || server_update_socket() != 0) 288*311827fbSnicm xtimeout = POLL_TIMEOUT; 289*311827fbSnicm 290*311827fbSnicm /* Do the poll. */ 291*311827fbSnicm if ((nfds = poll(pfds, nfds, xtimeout)) == -1) { 292*311827fbSnicm if (errno == EAGAIN || errno == EINTR) 293*311827fbSnicm continue; 294*311827fbSnicm fatal("poll failed"); 295*311827fbSnicm } 296*311827fbSnicm pfd = pfds; 297*311827fbSnicm 298*311827fbSnicm /* Handle server socket. */ 299*311827fbSnicm if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) 300*311827fbSnicm fatalx("lost server socket"); 301*311827fbSnicm if (pfd->revents & POLLIN) { 302*311827fbSnicm server_accept_client(srv_fd); 303*311827fbSnicm continue; 304*311827fbSnicm } 305*311827fbSnicm pfd++; 306*311827fbSnicm 307*311827fbSnicm /* Call second-based timers. */ 308*311827fbSnicm now = time(NULL); 309*311827fbSnicm if (now != last) { 310*311827fbSnicm last = now; 311*311827fbSnicm server_second_timers(); 312*311827fbSnicm } 313*311827fbSnicm 314*311827fbSnicm /* Set window names. */ 315*311827fbSnicm set_window_names(); 316*311827fbSnicm 317*311827fbSnicm /* 318*311827fbSnicm * Handle window and client sockets. Clients can create 319*311827fbSnicm * windows, so windows must come first to avoid messing up by 320*311827fbSnicm * increasing the array size. 321*311827fbSnicm */ 322*311827fbSnicm server_handle_windows(&pfd); 323*311827fbSnicm server_handle_clients(&pfd); 324*311827fbSnicm 325*311827fbSnicm /* 326*311827fbSnicm * If we have no sessions and clients left, let's get out 327*311827fbSnicm * of here... 328*311827fbSnicm */ 329*311827fbSnicm n = 0; 330*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 331*311827fbSnicm if (ARRAY_ITEM(&sessions, i) != NULL) 332*311827fbSnicm n++; 333*311827fbSnicm } 334*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 335*311827fbSnicm if (ARRAY_ITEM(&clients, i) != NULL) 336*311827fbSnicm n++; 337*311827fbSnicm } 338*311827fbSnicm if (n == 0) 339*311827fbSnicm break; 340*311827fbSnicm } 341*311827fbSnicm if (pfds != NULL) 342*311827fbSnicm xfree(pfds); 343*311827fbSnicm 344*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 345*311827fbSnicm if (ARRAY_ITEM(&sessions, i) != NULL) 346*311827fbSnicm session_destroy(ARRAY_ITEM(&sessions, i)); 347*311827fbSnicm } 348*311827fbSnicm ARRAY_FREE(&sessions); 349*311827fbSnicm 350*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 351*311827fbSnicm if (ARRAY_ITEM(&clients, i) != NULL) 352*311827fbSnicm server_lost_client(ARRAY_ITEM(&clients, i)); 353*311827fbSnicm } 354*311827fbSnicm ARRAY_FREE(&clients); 355*311827fbSnicm 356*311827fbSnicm key_bindings_free(); 357*311827fbSnicm 358*311827fbSnicm close(srv_fd); 359*311827fbSnicm 360*311827fbSnicm unlink(socket_path); 361*311827fbSnicm xfree(socket_path); 362*311827fbSnicm 363*311827fbSnicm options_free(&global_options); 364*311827fbSnicm options_free(&global_window_options); 365*311827fbSnicm if (server_password != NULL) 366*311827fbSnicm xfree(server_password); 367*311827fbSnicm 368*311827fbSnicm return (0); 369*311827fbSnicm } 370*311827fbSnicm 371*311827fbSnicm /* Kill all clients. */ 372*311827fbSnicm void 373*311827fbSnicm server_shutdown(void) 374*311827fbSnicm { 375*311827fbSnicm struct session *s; 376*311827fbSnicm struct client *c; 377*311827fbSnicm u_int i, j; 378*311827fbSnicm 379*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 380*311827fbSnicm s = ARRAY_ITEM(&sessions, i); 381*311827fbSnicm for (j = 0; j < ARRAY_LENGTH(&clients); j++) { 382*311827fbSnicm c = ARRAY_ITEM(&clients, j); 383*311827fbSnicm if (c != NULL && c->session == s) { 384*311827fbSnicm s = NULL; 385*311827fbSnicm break; 386*311827fbSnicm } 387*311827fbSnicm } 388*311827fbSnicm if (s != NULL) 389*311827fbSnicm session_destroy(s); 390*311827fbSnicm } 391*311827fbSnicm 392*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 393*311827fbSnicm c = ARRAY_ITEM(&clients, i); 394*311827fbSnicm if (c != NULL) 395*311827fbSnicm server_write_client(c, MSG_SHUTDOWN, NULL, 0); 396*311827fbSnicm } 397*311827fbSnicm } 398*311827fbSnicm 399*311827fbSnicm /* Handle SIGCHLD. */ 400*311827fbSnicm void 401*311827fbSnicm server_child_signal(void) 402*311827fbSnicm { 403*311827fbSnicm struct window *w; 404*311827fbSnicm struct window_pane *wp; 405*311827fbSnicm int status; 406*311827fbSnicm pid_t pid; 407*311827fbSnicm u_int i; 408*311827fbSnicm 409*311827fbSnicm for (;;) { 410*311827fbSnicm switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) { 411*311827fbSnicm case -1: 412*311827fbSnicm if (errno == ECHILD) 413*311827fbSnicm return; 414*311827fbSnicm fatal("waitpid"); 415*311827fbSnicm case 0: 416*311827fbSnicm return; 417*311827fbSnicm } 418*311827fbSnicm if (!WIFSTOPPED(status)) 419*311827fbSnicm continue; 420*311827fbSnicm if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) 421*311827fbSnicm continue; 422*311827fbSnicm 423*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 424*311827fbSnicm w = ARRAY_ITEM(&windows, i); 425*311827fbSnicm if (w == NULL) 426*311827fbSnicm continue; 427*311827fbSnicm TAILQ_FOREACH(wp, &w->panes, entry) { 428*311827fbSnicm if (wp->pid == pid) { 429*311827fbSnicm if (killpg(pid, SIGCONT) != 0) 430*311827fbSnicm kill(pid, SIGCONT); 431*311827fbSnicm } 432*311827fbSnicm } 433*311827fbSnicm } 434*311827fbSnicm } 435*311827fbSnicm } 436*311827fbSnicm 437*311827fbSnicm /* Fill window pollfds. */ 438*311827fbSnicm void 439*311827fbSnicm server_fill_windows(struct pollfd **pfd) 440*311827fbSnicm { 441*311827fbSnicm struct window *w; 442*311827fbSnicm struct window_pane *wp; 443*311827fbSnicm u_int i; 444*311827fbSnicm 445*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 446*311827fbSnicm w = ARRAY_ITEM(&windows, i); 447*311827fbSnicm if (w == NULL) 448*311827fbSnicm continue; 449*311827fbSnicm 450*311827fbSnicm TAILQ_FOREACH(wp, &w->panes, entry) { 451*311827fbSnicm (*pfd)->fd = wp->fd; 452*311827fbSnicm if (wp->fd != -1) { 453*311827fbSnicm (*pfd)->events = POLLIN; 454*311827fbSnicm if (BUFFER_USED(wp->out) > 0) 455*311827fbSnicm (*pfd)->events |= POLLOUT; 456*311827fbSnicm } 457*311827fbSnicm (*pfd)++; 458*311827fbSnicm } 459*311827fbSnicm } 460*311827fbSnicm } 461*311827fbSnicm 462*311827fbSnicm /* Handle window pollfds. */ 463*311827fbSnicm void 464*311827fbSnicm server_handle_windows(struct pollfd **pfd) 465*311827fbSnicm { 466*311827fbSnicm struct window *w; 467*311827fbSnicm struct window_pane *wp; 468*311827fbSnicm u_int i; 469*311827fbSnicm 470*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 471*311827fbSnicm w = ARRAY_ITEM(&windows, i); 472*311827fbSnicm if (w == NULL) 473*311827fbSnicm continue; 474*311827fbSnicm 475*311827fbSnicm TAILQ_FOREACH(wp, &w->panes, entry) { 476*311827fbSnicm if (wp->fd != -1) { 477*311827fbSnicm if (buffer_poll(*pfd, wp->in, wp->out) != 0) { 478*311827fbSnicm close(wp->fd); 479*311827fbSnicm wp->fd = -1; 480*311827fbSnicm } else 481*311827fbSnicm server_handle_window(w, wp); 482*311827fbSnicm } 483*311827fbSnicm (*pfd)++; 484*311827fbSnicm } 485*311827fbSnicm 486*311827fbSnicm server_check_window(w); 487*311827fbSnicm } 488*311827fbSnicm } 489*311827fbSnicm 490*311827fbSnicm /* Check for general redraw on client. */ 491*311827fbSnicm void 492*311827fbSnicm server_check_redraw(struct client *c) 493*311827fbSnicm { 494*311827fbSnicm struct session *s; 495*311827fbSnicm struct window_pane *wp; 496*311827fbSnicm char title[512]; 497*311827fbSnicm int flags, redraw; 498*311827fbSnicm 499*311827fbSnicm if (c == NULL || c->session == NULL) 500*311827fbSnicm return; 501*311827fbSnicm s = c->session; 502*311827fbSnicm 503*311827fbSnicm flags = c->tty.flags & TTY_FREEZE; 504*311827fbSnicm c->tty.flags &= ~TTY_FREEZE; 505*311827fbSnicm 506*311827fbSnicm if (options_get_number(&s->options, "set-titles")) { 507*311827fbSnicm xsnprintf(title, sizeof title, "%s:%u:%s - \"%s\"", 508*311827fbSnicm s->name, s->curw->idx, s->curw->window->name, 509*311827fbSnicm s->curw->window->active->screen->title); 510*311827fbSnicm if (c->title == NULL || strcmp(title, c->title) != 0) { 511*311827fbSnicm if (c->title != NULL) 512*311827fbSnicm xfree(c->title); 513*311827fbSnicm c->title = xstrdup(title); 514*311827fbSnicm tty_set_title(&c->tty, c->title); 515*311827fbSnicm } 516*311827fbSnicm } 517*311827fbSnicm 518*311827fbSnicm if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { 519*311827fbSnicm if (c->message_string != NULL) 520*311827fbSnicm redraw = status_message_redraw(c); 521*311827fbSnicm else if (c->prompt_string != NULL) 522*311827fbSnicm redraw = status_prompt_redraw(c); 523*311827fbSnicm else 524*311827fbSnicm redraw = status_redraw(c); 525*311827fbSnicm if (!redraw) 526*311827fbSnicm c->flags &= ~CLIENT_STATUS; 527*311827fbSnicm } 528*311827fbSnicm 529*311827fbSnicm if (c->flags & CLIENT_REDRAW) { 530*311827fbSnicm if (server_locked) 531*311827fbSnicm server_redraw_locked(c); 532*311827fbSnicm else 533*311827fbSnicm screen_redraw_screen(c); 534*311827fbSnicm c->flags &= ~CLIENT_STATUS; 535*311827fbSnicm } else { 536*311827fbSnicm TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { 537*311827fbSnicm if (wp->flags & PANE_REDRAW) 538*311827fbSnicm screen_redraw_pane(c, wp); 539*311827fbSnicm } 540*311827fbSnicm } 541*311827fbSnicm 542*311827fbSnicm if (c->flags & CLIENT_STATUS) 543*311827fbSnicm screen_redraw_status(c); 544*311827fbSnicm 545*311827fbSnicm c->tty.flags |= flags; 546*311827fbSnicm 547*311827fbSnicm c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); 548*311827fbSnicm } 549*311827fbSnicm 550*311827fbSnicm /* Redraw client when locked. */ 551*311827fbSnicm void 552*311827fbSnicm server_redraw_locked(struct client *c) 553*311827fbSnicm { 554*311827fbSnicm struct screen_write_ctx ctx; 555*311827fbSnicm struct screen screen; 556*311827fbSnicm u_int colour, xx, yy, i; 557*311827fbSnicm int style; 558*311827fbSnicm 559*311827fbSnicm xx = c->tty.sx; 560*311827fbSnicm yy = c->tty.sy - 1; 561*311827fbSnicm if (xx == 0 || yy == 0) 562*311827fbSnicm return; 563*311827fbSnicm colour = options_get_number( 564*311827fbSnicm &global_window_options, "clock-mode-colour"); 565*311827fbSnicm style = options_get_number( 566*311827fbSnicm &global_window_options, "clock-mode-style"); 567*311827fbSnicm 568*311827fbSnicm screen_init(&screen, xx, yy, 0); 569*311827fbSnicm 570*311827fbSnicm screen_write_start(&ctx, NULL, &screen); 571*311827fbSnicm clock_draw(&ctx, colour, style); 572*311827fbSnicm screen_write_stop(&ctx); 573*311827fbSnicm 574*311827fbSnicm for (i = 0; i < screen_size_y(&screen); i++) 575*311827fbSnicm tty_draw_line(&c->tty, &screen, i, 0, 0); 576*311827fbSnicm screen_redraw_status(c); 577*311827fbSnicm 578*311827fbSnicm screen_free(&screen); 579*311827fbSnicm } 580*311827fbSnicm 581*311827fbSnicm /* Check for timers on client. */ 582*311827fbSnicm void 583*311827fbSnicm server_check_timers(struct client *c) 584*311827fbSnicm { 585*311827fbSnicm struct session *s; 586*311827fbSnicm struct timeval tv; 587*311827fbSnicm u_int interval; 588*311827fbSnicm 589*311827fbSnicm if (c == NULL || c->session == NULL) 590*311827fbSnicm return; 591*311827fbSnicm s = c->session; 592*311827fbSnicm 593*311827fbSnicm if (gettimeofday(&tv, NULL) != 0) 594*311827fbSnicm fatal("gettimeofday"); 595*311827fbSnicm 596*311827fbSnicm if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) 597*311827fbSnicm status_message_clear(c); 598*311827fbSnicm 599*311827fbSnicm if (c->message_string != NULL || c->prompt_string != NULL) { 600*311827fbSnicm /* 601*311827fbSnicm * Don't need timed redraw for messages/prompts so bail now. 602*311827fbSnicm * The status timer isn't reset when they are redrawn anyway. 603*311827fbSnicm */ 604*311827fbSnicm return; 605*311827fbSnicm } 606*311827fbSnicm if (!options_get_number(&s->options, "status")) 607*311827fbSnicm return; 608*311827fbSnicm 609*311827fbSnicm /* Check timer; resolution is only a second so don't be too clever. */ 610*311827fbSnicm interval = options_get_number(&s->options, "status-interval"); 611*311827fbSnicm if (interval == 0) 612*311827fbSnicm return; 613*311827fbSnicm if (tv.tv_sec < c->status_timer.tv_sec || 614*311827fbSnicm ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) 615*311827fbSnicm c->flags |= CLIENT_STATUS; 616*311827fbSnicm } 617*311827fbSnicm 618*311827fbSnicm /* Fill client pollfds. */ 619*311827fbSnicm void 620*311827fbSnicm server_fill_clients(struct pollfd **pfd) 621*311827fbSnicm { 622*311827fbSnicm struct client *c; 623*311827fbSnicm struct window *w; 624*311827fbSnicm struct window_pane *wp; 625*311827fbSnicm u_int i; 626*311827fbSnicm 627*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 628*311827fbSnicm c = ARRAY_ITEM(&clients, i); 629*311827fbSnicm 630*311827fbSnicm server_check_timers(c); 631*311827fbSnicm server_check_redraw(c); 632*311827fbSnicm 633*311827fbSnicm if (c == NULL) 634*311827fbSnicm (*pfd)->fd = -1; 635*311827fbSnicm else { 636*311827fbSnicm (*pfd)->fd = c->fd; 637*311827fbSnicm (*pfd)->events = POLLIN; 638*311827fbSnicm if (BUFFER_USED(c->out) > 0) 639*311827fbSnicm (*pfd)->events |= POLLOUT; 640*311827fbSnicm } 641*311827fbSnicm (*pfd)++; 642*311827fbSnicm 643*311827fbSnicm if (c == NULL || c->flags & CLIENT_SUSPENDED || 644*311827fbSnicm c->tty.fd == -1 || c->session == NULL) 645*311827fbSnicm (*pfd)->fd = -1; 646*311827fbSnicm else { 647*311827fbSnicm (*pfd)->fd = c->tty.fd; 648*311827fbSnicm (*pfd)->events = POLLIN; 649*311827fbSnicm if (BUFFER_USED(c->tty.out) > 0) 650*311827fbSnicm (*pfd)->events |= POLLOUT; 651*311827fbSnicm } 652*311827fbSnicm (*pfd)++; 653*311827fbSnicm } 654*311827fbSnicm 655*311827fbSnicm /* 656*311827fbSnicm * Clear any window redraw flags (will have been redrawn as part of 657*311827fbSnicm * client). 658*311827fbSnicm */ 659*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 660*311827fbSnicm w = ARRAY_ITEM(&windows, i); 661*311827fbSnicm if (w == NULL) 662*311827fbSnicm continue; 663*311827fbSnicm 664*311827fbSnicm w->flags &= ~WINDOW_REDRAW; 665*311827fbSnicm TAILQ_FOREACH(wp, &w->panes, entry) 666*311827fbSnicm wp->flags &= ~PANE_REDRAW; 667*311827fbSnicm } 668*311827fbSnicm } 669*311827fbSnicm 670*311827fbSnicm /* Handle client pollfds. */ 671*311827fbSnicm void 672*311827fbSnicm server_handle_clients(struct pollfd **pfd) 673*311827fbSnicm { 674*311827fbSnicm struct client *c; 675*311827fbSnicm u_int i; 676*311827fbSnicm 677*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 678*311827fbSnicm c = ARRAY_ITEM(&clients, i); 679*311827fbSnicm 680*311827fbSnicm if (c != NULL) { 681*311827fbSnicm if (buffer_poll(*pfd, c->in, c->out) != 0) { 682*311827fbSnicm server_lost_client(c); 683*311827fbSnicm (*pfd) += 2; 684*311827fbSnicm continue; 685*311827fbSnicm } else 686*311827fbSnicm server_msg_dispatch(c); 687*311827fbSnicm } 688*311827fbSnicm (*pfd)++; 689*311827fbSnicm 690*311827fbSnicm if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && 691*311827fbSnicm c->tty.fd != -1 && c->session != NULL) { 692*311827fbSnicm if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0) 693*311827fbSnicm server_lost_client(c); 694*311827fbSnicm else 695*311827fbSnicm server_handle_client(c); 696*311827fbSnicm } 697*311827fbSnicm (*pfd)++; 698*311827fbSnicm } 699*311827fbSnicm } 700*311827fbSnicm 701*311827fbSnicm /* accept(2) and create new client. */ 702*311827fbSnicm struct client * 703*311827fbSnicm server_accept_client(int srv_fd) 704*311827fbSnicm { 705*311827fbSnicm struct sockaddr_storage sa; 706*311827fbSnicm socklen_t slen = sizeof sa; 707*311827fbSnicm int fd; 708*311827fbSnicm 709*311827fbSnicm fd = accept(srv_fd, (struct sockaddr *) &sa, &slen); 710*311827fbSnicm if (fd == -1) { 711*311827fbSnicm if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) 712*311827fbSnicm return (NULL); 713*311827fbSnicm fatal("accept failed"); 714*311827fbSnicm } 715*311827fbSnicm if (sigterm) { 716*311827fbSnicm close(fd); 717*311827fbSnicm return (NULL); 718*311827fbSnicm } 719*311827fbSnicm return (server_create_client(fd)); 720*311827fbSnicm } 721*311827fbSnicm 722*311827fbSnicm /* Input data from client. */ 723*311827fbSnicm void 724*311827fbSnicm server_handle_client(struct client *c) 725*311827fbSnicm { 726*311827fbSnicm struct window_pane *wp; 727*311827fbSnicm struct screen *s; 728*311827fbSnicm struct timeval tv; 729*311827fbSnicm struct key_binding *bd; 730*311827fbSnicm int key, prefix, status, xtimeout; 731*311827fbSnicm int mode; 732*311827fbSnicm u_char mouse[3]; 733*311827fbSnicm 734*311827fbSnicm xtimeout = options_get_number(&c->session->options, "repeat-time"); 735*311827fbSnicm if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { 736*311827fbSnicm if (gettimeofday(&tv, NULL) != 0) 737*311827fbSnicm fatal("gettimeofday"); 738*311827fbSnicm if (timercmp(&tv, &c->repeat_timer, >)) 739*311827fbSnicm c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); 740*311827fbSnicm } 741*311827fbSnicm 742*311827fbSnicm /* Process keys. */ 743*311827fbSnicm prefix = options_get_number(&c->session->options, "prefix"); 744*311827fbSnicm while (tty_keys_next(&c->tty, &key, mouse) == 0) { 745*311827fbSnicm server_activity = time(NULL); 746*311827fbSnicm 747*311827fbSnicm if (c->session == NULL) 748*311827fbSnicm return; 749*311827fbSnicm wp = c->session->curw->window->active; /* could die */ 750*311827fbSnicm 751*311827fbSnicm status_message_clear(c); 752*311827fbSnicm if (c->prompt_string != NULL) { 753*311827fbSnicm status_prompt_key(c, key); 754*311827fbSnicm continue; 755*311827fbSnicm } 756*311827fbSnicm if (server_locked) 757*311827fbSnicm continue; 758*311827fbSnicm 759*311827fbSnicm /* Check for mouse keys. */ 760*311827fbSnicm if (key == KEYC_MOUSE) { 761*311827fbSnicm window_pane_mouse(wp, c, mouse[0], mouse[1], mouse[2]); 762*311827fbSnicm continue; 763*311827fbSnicm } 764*311827fbSnicm 765*311827fbSnicm /* No previous prefix key. */ 766*311827fbSnicm if (!(c->flags & CLIENT_PREFIX)) { 767*311827fbSnicm if (key == prefix) 768*311827fbSnicm c->flags |= CLIENT_PREFIX; 769*311827fbSnicm else 770*311827fbSnicm window_pane_key(wp, c, key); 771*311827fbSnicm continue; 772*311827fbSnicm } 773*311827fbSnicm 774*311827fbSnicm /* Prefix key already pressed. Reset prefix and lookup key. */ 775*311827fbSnicm c->flags &= ~CLIENT_PREFIX; 776*311827fbSnicm if ((bd = key_bindings_lookup(key)) == NULL) { 777*311827fbSnicm /* If repeating, treat this as a key, else ignore. */ 778*311827fbSnicm if (c->flags & CLIENT_REPEAT) { 779*311827fbSnicm c->flags &= ~CLIENT_REPEAT; 780*311827fbSnicm if (key == prefix) 781*311827fbSnicm c->flags |= CLIENT_PREFIX; 782*311827fbSnicm else 783*311827fbSnicm window_pane_key(wp, c, key); 784*311827fbSnicm } 785*311827fbSnicm continue; 786*311827fbSnicm } 787*311827fbSnicm 788*311827fbSnicm /* If already repeating, but this key can't repeat, skip it. */ 789*311827fbSnicm if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { 790*311827fbSnicm c->flags &= ~CLIENT_REPEAT; 791*311827fbSnicm if (key == prefix) 792*311827fbSnicm c->flags |= CLIENT_PREFIX; 793*311827fbSnicm else 794*311827fbSnicm window_pane_key(wp, c, key); 795*311827fbSnicm continue; 796*311827fbSnicm } 797*311827fbSnicm 798*311827fbSnicm /* If this key can repeat, reset the repeat flags and timer. */ 799*311827fbSnicm if (xtimeout != 0 && bd->can_repeat) { 800*311827fbSnicm c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; 801*311827fbSnicm 802*311827fbSnicm tv.tv_sec = xtimeout / 1000; 803*311827fbSnicm tv.tv_usec = (xtimeout % 1000) * 1000L; 804*311827fbSnicm if (gettimeofday(&c->repeat_timer, NULL) != 0) 805*311827fbSnicm fatal("gettimeofday"); 806*311827fbSnicm timeradd(&c->repeat_timer, &tv, &c->repeat_timer); 807*311827fbSnicm } 808*311827fbSnicm 809*311827fbSnicm /* Dispatch the command. */ 810*311827fbSnicm key_bindings_dispatch(bd, c); 811*311827fbSnicm } 812*311827fbSnicm if (c->session == NULL) 813*311827fbSnicm return; 814*311827fbSnicm wp = c->session->curw->window->active; /* could die - do each loop */ 815*311827fbSnicm s = wp->screen; 816*311827fbSnicm 817*311827fbSnicm /* Ensure cursor position and mode settings. */ 818*311827fbSnicm status = options_get_number(&c->session->options, "status"); 819*311827fbSnicm if (wp->yoff + s->cy < c->tty.sy - status) 820*311827fbSnicm tty_cursor(&c->tty, s->cx, s->cy, wp->xoff, wp->yoff); 821*311827fbSnicm 822*311827fbSnicm mode = s->mode; 823*311827fbSnicm if (server_locked) 824*311827fbSnicm mode &= ~TTY_NOCURSOR; 825*311827fbSnicm tty_update_mode(&c->tty, mode); 826*311827fbSnicm } 827*311827fbSnicm 828*311827fbSnicm /* Lost a client. */ 829*311827fbSnicm void 830*311827fbSnicm server_lost_client(struct client *c) 831*311827fbSnicm { 832*311827fbSnicm u_int i; 833*311827fbSnicm 834*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 835*311827fbSnicm if (ARRAY_ITEM(&clients, i) == c) 836*311827fbSnicm ARRAY_SET(&clients, i, NULL); 837*311827fbSnicm } 838*311827fbSnicm 839*311827fbSnicm tty_free(&c->tty, c->flags & CLIENT_SUSPENDED); 840*311827fbSnicm 841*311827fbSnicm screen_free(&c->status); 842*311827fbSnicm 843*311827fbSnicm if (c->title != NULL) 844*311827fbSnicm xfree(c->title); 845*311827fbSnicm 846*311827fbSnicm if (c->message_string != NULL) 847*311827fbSnicm xfree(c->message_string); 848*311827fbSnicm 849*311827fbSnicm if (c->prompt_string != NULL) 850*311827fbSnicm xfree(c->prompt_string); 851*311827fbSnicm if (c->prompt_buffer != NULL) 852*311827fbSnicm xfree(c->prompt_buffer); 853*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) 854*311827fbSnicm xfree(ARRAY_ITEM(&c->prompt_hdata, i)); 855*311827fbSnicm ARRAY_FREE(&c->prompt_hdata); 856*311827fbSnicm 857*311827fbSnicm if (c->cwd != NULL) 858*311827fbSnicm xfree(c->cwd); 859*311827fbSnicm 860*311827fbSnicm close(c->fd); 861*311827fbSnicm buffer_destroy(c->in); 862*311827fbSnicm buffer_destroy(c->out); 863*311827fbSnicm xfree(c); 864*311827fbSnicm 865*311827fbSnicm recalculate_sizes(); 866*311827fbSnicm } 867*311827fbSnicm 868*311827fbSnicm /* Handle window data. */ 869*311827fbSnicm void 870*311827fbSnicm server_handle_window(struct window *w, struct window_pane *wp) 871*311827fbSnicm { 872*311827fbSnicm struct session *s; 873*311827fbSnicm u_int i; 874*311827fbSnicm int update; 875*311827fbSnicm 876*311827fbSnicm window_pane_parse(wp); 877*311827fbSnicm 878*311827fbSnicm if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0) 879*311827fbSnicm return; 880*311827fbSnicm 881*311827fbSnicm update = 0; 882*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 883*311827fbSnicm s = ARRAY_ITEM(&sessions, i); 884*311827fbSnicm if (s == NULL || !session_has(s, w)) 885*311827fbSnicm continue; 886*311827fbSnicm 887*311827fbSnicm update += server_check_window_bell(s, w, wp); 888*311827fbSnicm update += server_check_window_activity(s, w); 889*311827fbSnicm update += server_check_window_content(s, w, wp); 890*311827fbSnicm } 891*311827fbSnicm if (update) 892*311827fbSnicm server_status_window(w); 893*311827fbSnicm 894*311827fbSnicm w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); 895*311827fbSnicm } 896*311827fbSnicm 897*311827fbSnicm int 898*311827fbSnicm server_check_window_bell( 899*311827fbSnicm struct session *s, struct window *w, struct window_pane *wp) 900*311827fbSnicm { 901*311827fbSnicm struct client *c; 902*311827fbSnicm u_int i; 903*311827fbSnicm int action; 904*311827fbSnicm 905*311827fbSnicm if (!(w->flags & WINDOW_BELL)) 906*311827fbSnicm return (0); 907*311827fbSnicm if (session_alert_has_window(s, w, WINDOW_BELL)) 908*311827fbSnicm return (0); 909*311827fbSnicm session_alert_add(s, w, WINDOW_BELL); 910*311827fbSnicm 911*311827fbSnicm action = options_get_number(&s->options, "bell-action"); 912*311827fbSnicm switch (action) { 913*311827fbSnicm case BELL_ANY: 914*311827fbSnicm if (s->flags & SESSION_UNATTACHED) 915*311827fbSnicm break; 916*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 917*311827fbSnicm c = ARRAY_ITEM(&clients, i); 918*311827fbSnicm if (c != NULL && c->session == s) 919*311827fbSnicm tty_putcode(&c->tty, TTYC_BEL); 920*311827fbSnicm } 921*311827fbSnicm break; 922*311827fbSnicm case BELL_CURRENT: 923*311827fbSnicm if (w->active != wp) 924*311827fbSnicm break; 925*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 926*311827fbSnicm c = ARRAY_ITEM(&clients, i); 927*311827fbSnicm if (c != NULL && c->session == s) 928*311827fbSnicm tty_putcode(&c->tty, TTYC_BEL); 929*311827fbSnicm } 930*311827fbSnicm break; 931*311827fbSnicm } 932*311827fbSnicm return (1); 933*311827fbSnicm } 934*311827fbSnicm 935*311827fbSnicm int 936*311827fbSnicm server_check_window_activity(struct session *s, struct window *w) 937*311827fbSnicm { 938*311827fbSnicm if (!(w->flags & WINDOW_ACTIVITY)) 939*311827fbSnicm return (0); 940*311827fbSnicm if (!options_get_number(&w->options, "monitor-activity")) 941*311827fbSnicm return (0); 942*311827fbSnicm if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) 943*311827fbSnicm return (0); 944*311827fbSnicm session_alert_add(s, w, WINDOW_ACTIVITY); 945*311827fbSnicm return (1); 946*311827fbSnicm } 947*311827fbSnicm 948*311827fbSnicm int 949*311827fbSnicm server_check_window_content( 950*311827fbSnicm struct session *s, struct window *w, struct window_pane *wp) 951*311827fbSnicm { 952*311827fbSnicm char *found, *ptr; 953*311827fbSnicm 954*311827fbSnicm if (!(w->flags & WINDOW_CONTENT)) 955*311827fbSnicm return (0); 956*311827fbSnicm if ((ptr = options_get_string(&w->options, "monitor-content")) == NULL) 957*311827fbSnicm return (0); 958*311827fbSnicm if (*ptr == '\0') 959*311827fbSnicm return (0); 960*311827fbSnicm if (session_alert_has_window(s, w, WINDOW_CONTENT)) 961*311827fbSnicm return (0); 962*311827fbSnicm if ((found = window_pane_search(wp, ptr)) == NULL) 963*311827fbSnicm return (0); 964*311827fbSnicm session_alert_add(s, w, WINDOW_CONTENT); 965*311827fbSnicm xfree(found); 966*311827fbSnicm return (1); 967*311827fbSnicm } 968*311827fbSnicm 969*311827fbSnicm /* Check if window still exists.. */ 970*311827fbSnicm void 971*311827fbSnicm server_check_window(struct window *w) 972*311827fbSnicm { 973*311827fbSnicm struct window_pane *wp, *wq; 974*311827fbSnicm struct client *c; 975*311827fbSnicm struct session *s; 976*311827fbSnicm struct winlink *wl; 977*311827fbSnicm u_int i, j; 978*311827fbSnicm int destroyed, flag; 979*311827fbSnicm 980*311827fbSnicm flag = options_get_number(&w->options, "remain-on-exit"); 981*311827fbSnicm 982*311827fbSnicm destroyed = 1; 983*311827fbSnicm 984*311827fbSnicm wp = TAILQ_FIRST(&w->panes); 985*311827fbSnicm while (wp != NULL) { 986*311827fbSnicm wq = TAILQ_NEXT(wp, entry); 987*311827fbSnicm if (wp->fd != -1) 988*311827fbSnicm destroyed = 0; 989*311827fbSnicm else if (!flag) { 990*311827fbSnicm window_remove_pane(w, wp); 991*311827fbSnicm server_redraw_window(w); 992*311827fbSnicm layout_refresh(w, 0); 993*311827fbSnicm } 994*311827fbSnicm wp = wq; 995*311827fbSnicm } 996*311827fbSnicm 997*311827fbSnicm if (!destroyed) 998*311827fbSnicm return; 999*311827fbSnicm 1000*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 1001*311827fbSnicm s = ARRAY_ITEM(&sessions, i); 1002*311827fbSnicm if (s == NULL) 1003*311827fbSnicm continue; 1004*311827fbSnicm if (!session_has(s, w)) 1005*311827fbSnicm continue; 1006*311827fbSnicm 1007*311827fbSnicm restart: 1008*311827fbSnicm /* Detach window and either redraw or kill clients. */ 1009*311827fbSnicm RB_FOREACH(wl, winlinks, &s->windows) { 1010*311827fbSnicm if (wl->window != w) 1011*311827fbSnicm continue; 1012*311827fbSnicm destroyed = session_detach(s, wl); 1013*311827fbSnicm for (j = 0; j < ARRAY_LENGTH(&clients); j++) { 1014*311827fbSnicm c = ARRAY_ITEM(&clients, j); 1015*311827fbSnicm if (c == NULL || c->session != s) 1016*311827fbSnicm continue; 1017*311827fbSnicm if (!destroyed) { 1018*311827fbSnicm server_redraw_client(c); 1019*311827fbSnicm continue; 1020*311827fbSnicm } 1021*311827fbSnicm c->session = NULL; 1022*311827fbSnicm server_write_client(c, MSG_EXIT, NULL, 0); 1023*311827fbSnicm } 1024*311827fbSnicm /* If the session was destroyed, bail now. */ 1025*311827fbSnicm if (destroyed) 1026*311827fbSnicm break; 1027*311827fbSnicm goto restart; 1028*311827fbSnicm } 1029*311827fbSnicm } 1030*311827fbSnicm 1031*311827fbSnicm recalculate_sizes(); 1032*311827fbSnicm } 1033*311827fbSnicm 1034*311827fbSnicm /* Call any once-per-second timers. */ 1035*311827fbSnicm void 1036*311827fbSnicm server_second_timers(void) 1037*311827fbSnicm { 1038*311827fbSnicm struct window *w; 1039*311827fbSnicm struct window_pane *wp; 1040*311827fbSnicm u_int i; 1041*311827fbSnicm int xtimeout; 1042*311827fbSnicm struct tm now, then; 1043*311827fbSnicm static time_t last_t = 0; 1044*311827fbSnicm time_t t; 1045*311827fbSnicm 1046*311827fbSnicm t = time(NULL); 1047*311827fbSnicm xtimeout = options_get_number(&global_options, "lock-after-time"); 1048*311827fbSnicm if (xtimeout > 0 && t > server_activity + xtimeout) 1049*311827fbSnicm server_lock(); 1050*311827fbSnicm 1051*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&windows); i++) { 1052*311827fbSnicm w = ARRAY_ITEM(&windows, i); 1053*311827fbSnicm if (w == NULL) 1054*311827fbSnicm continue; 1055*311827fbSnicm 1056*311827fbSnicm TAILQ_FOREACH(wp, &w->panes, entry) { 1057*311827fbSnicm if (wp->mode != NULL && wp->mode->timer != NULL) 1058*311827fbSnicm wp->mode->timer(wp); 1059*311827fbSnicm } 1060*311827fbSnicm } 1061*311827fbSnicm 1062*311827fbSnicm /* Check for a minute having passed. */ 1063*311827fbSnicm gmtime_r(&t, &now); 1064*311827fbSnicm gmtime_r(&last_t, &then); 1065*311827fbSnicm if (now.tm_min == then.tm_min) 1066*311827fbSnicm return; 1067*311827fbSnicm last_t = t; 1068*311827fbSnicm 1069*311827fbSnicm /* If locked, redraw all clients. */ 1070*311827fbSnicm if (server_locked) { 1071*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&clients); i++) { 1072*311827fbSnicm if (ARRAY_ITEM(&clients, i) != NULL) 1073*311827fbSnicm server_redraw_client(ARRAY_ITEM(&clients, i)); 1074*311827fbSnicm } 1075*311827fbSnicm } 1076*311827fbSnicm } 1077*311827fbSnicm 1078*311827fbSnicm /* Update socket execute permissions based on whether sessions are attached. */ 1079*311827fbSnicm int 1080*311827fbSnicm server_update_socket(void) 1081*311827fbSnicm { 1082*311827fbSnicm struct session *s; 1083*311827fbSnicm u_int i; 1084*311827fbSnicm static int last = -1; 1085*311827fbSnicm int n; 1086*311827fbSnicm 1087*311827fbSnicm n = 0; 1088*311827fbSnicm for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { 1089*311827fbSnicm s = ARRAY_ITEM(&sessions, i); 1090*311827fbSnicm if (s != NULL && !(s->flags & SESSION_UNATTACHED)) { 1091*311827fbSnicm n++; 1092*311827fbSnicm break; 1093*311827fbSnicm } 1094*311827fbSnicm } 1095*311827fbSnicm 1096*311827fbSnicm if (n != last) { 1097*311827fbSnicm last = n; 1098*311827fbSnicm if (n != 0) 1099*311827fbSnicm chmod(socket_path, S_IRWXU); 1100*311827fbSnicm else 1101*311827fbSnicm chmod(socket_path, S_IRUSR|S_IWUSR); 1102*311827fbSnicm } 1103*311827fbSnicm 1104*311827fbSnicm return (n); 1105*311827fbSnicm } 1106