1*514fd64dSnicm /* $OpenBSD: server.c,v 1.177 2017/10/12 11:32:27 nicm Exp $ */ 2311827fbSnicm 3311827fbSnicm /* 498ca8272Snicm * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5311827fbSnicm * 6311827fbSnicm * Permission to use, copy, modify, and distribute this software for any 7311827fbSnicm * purpose with or without fee is hereby granted, provided that the above 8311827fbSnicm * copyright notice and this permission notice appear in all copies. 9311827fbSnicm * 10311827fbSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11311827fbSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12311827fbSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13311827fbSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14311827fbSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15311827fbSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16311827fbSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17311827fbSnicm */ 18311827fbSnicm 19311827fbSnicm #include <sys/types.h> 20311827fbSnicm #include <sys/ioctl.h> 21311827fbSnicm #include <sys/socket.h> 22311827fbSnicm #include <sys/stat.h> 23311827fbSnicm #include <sys/un.h> 24311827fbSnicm #include <sys/wait.h> 25311827fbSnicm 26311827fbSnicm #include <errno.h> 277724d0b0Snicm #include <event.h> 28311827fbSnicm #include <fcntl.h> 29a575a2dfSnicm #include <paths.h> 30311827fbSnicm #include <signal.h> 31311827fbSnicm #include <stdio.h> 32311827fbSnicm #include <stdlib.h> 33311827fbSnicm #include <string.h> 34311827fbSnicm #include <termios.h> 35311827fbSnicm #include <time.h> 36311827fbSnicm #include <unistd.h> 37311827fbSnicm 38311827fbSnicm #include "tmux.h" 39311827fbSnicm 40311827fbSnicm /* 41311827fbSnicm * Main server functions. 42311827fbSnicm */ 43311827fbSnicm 44311827fbSnicm struct clients clients; 45311827fbSnicm 465b8ac713Snicm struct tmuxproc *server_proc; 479883b791Snicm static int server_fd; 489883b791Snicm static int server_exit; 499883b791Snicm static struct event server_ev_accept; 50b7fa064bSnicm 517519eda3Snicm struct cmd_find_state marked_pane; 522986c025Snicm 539883b791Snicm static int server_create_socket(void); 549883b791Snicm static int server_loop(void); 559883b791Snicm static void server_send_exit(void); 569883b791Snicm static void server_accept(int, short, void *); 579883b791Snicm static void server_signal(int); 589883b791Snicm static void server_child_signal(void); 599883b791Snicm static void server_child_exited(pid_t, int); 609883b791Snicm static void server_child_stopped(pid_t, int); 61b7fa064bSnicm 622986c025Snicm /* Set marked pane. */ 632986c025Snicm void 642986c025Snicm server_set_marked(struct session *s, struct winlink *wl, struct window_pane *wp) 652986c025Snicm { 6693e732aaSnicm cmd_find_clear_state(&marked_pane, 0); 677519eda3Snicm marked_pane.s = s; 687519eda3Snicm marked_pane.wl = wl; 697519eda3Snicm marked_pane.w = wl->window; 707519eda3Snicm marked_pane.wp = wp; 712986c025Snicm } 722986c025Snicm 732986c025Snicm /* Clear marked pane. */ 742986c025Snicm void 752986c025Snicm server_clear_marked(void) 762986c025Snicm { 7793e732aaSnicm cmd_find_clear_state(&marked_pane, 0); 782986c025Snicm } 792986c025Snicm 802986c025Snicm /* Is this the marked pane? */ 812986c025Snicm int 822986c025Snicm server_is_marked(struct session *s, struct winlink *wl, struct window_pane *wp) 832986c025Snicm { 842986c025Snicm if (s == NULL || wl == NULL || wp == NULL) 852986c025Snicm return (0); 867519eda3Snicm if (marked_pane.s != s || marked_pane.wl != wl) 872986c025Snicm return (0); 887519eda3Snicm if (marked_pane.wp != wp) 892986c025Snicm return (0); 902986c025Snicm return (server_check_marked()); 912986c025Snicm } 922986c025Snicm 932986c025Snicm /* Check if the marked pane is still valid. */ 942986c025Snicm int 952986c025Snicm server_check_marked(void) 962986c025Snicm { 977519eda3Snicm return (cmd_find_valid_state(&marked_pane)); 982986c025Snicm } 992986c025Snicm 10089654e7cSnicm /* Create server socket. */ 1019883b791Snicm static int 10289654e7cSnicm server_create_socket(void) 103311827fbSnicm { 10489654e7cSnicm struct sockaddr_un sa; 10589654e7cSnicm size_t size; 10689654e7cSnicm mode_t mask; 107a0ee4254Snicm int fd; 10889654e7cSnicm 10989654e7cSnicm memset(&sa, 0, sizeof sa); 11089654e7cSnicm sa.sun_family = AF_UNIX; 11189654e7cSnicm size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); 11289654e7cSnicm if (size >= sizeof sa.sun_path) { 11389654e7cSnicm errno = ENAMETOOLONG; 114d53cf33dSnicm return (-1); 11589654e7cSnicm } 11689654e7cSnicm unlink(sa.sun_path); 11789654e7cSnicm 11889654e7cSnicm if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 119d53cf33dSnicm return (-1); 12089654e7cSnicm 1217394227cSnicm mask = umask(S_IXUSR|S_IXGRP|S_IRWXO); 122fb807b18Snicm if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) { 123fb807b18Snicm close(fd); 124d53cf33dSnicm return (-1); 125fb807b18Snicm } 12689654e7cSnicm umask(mask); 12789654e7cSnicm 128fb807b18Snicm if (listen(fd, 128) == -1) { 129fb807b18Snicm close(fd); 130d53cf33dSnicm return (-1); 131fb807b18Snicm } 132a0ee4254Snicm setblocking(fd, 0); 133311827fbSnicm 13489654e7cSnicm return (fd); 13589654e7cSnicm } 136311827fbSnicm 137311827fbSnicm /* Fork new server. */ 138311827fbSnicm int 139c37a9299Snicm server_start(struct tmuxproc *client, struct event_base *base, int lockfd, 140c37a9299Snicm char *lockfile) 141311827fbSnicm { 1424e7bd783Snicm int pair[2]; 1431a432fefSnicm struct job *job; 144189d1393Snicm sigset_t set, oldset; 145311827fbSnicm 146311827fbSnicm if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) 147311827fbSnicm fatal("socketpair failed"); 148311827fbSnicm 149189d1393Snicm sigfillset(&set); 150189d1393Snicm sigprocmask(SIG_BLOCK, &set, &oldset); 151c37a9299Snicm switch (fork()) { 152c37a9299Snicm case -1: 153c37a9299Snicm fatal("fork failed"); 154c37a9299Snicm case 0: 155c37a9299Snicm break; 156c37a9299Snicm default: 157189d1393Snicm sigprocmask(SIG_SETMASK, &oldset, NULL); 158311827fbSnicm close(pair[1]); 159311827fbSnicm return (pair[0]); 160311827fbSnicm } 161311827fbSnicm close(pair[0]); 162c37a9299Snicm if (daemon(1, 0) != 0) 163c37a9299Snicm fatal("daemon failed"); 16489b52a5bSnicm proc_clear_signals(client, 0); 165c37a9299Snicm if (event_reinit(base) != 0) 166c37a9299Snicm fatalx("event_reinit failed"); 167c37a9299Snicm server_proc = proc_start("server"); 168c37a9299Snicm proc_set_signals(server_proc, server_signal); 169189d1393Snicm sigprocmask(SIG_SETMASK, &oldset, NULL); 170c37a9299Snicm 17179c9b201Snicm if (log_get_level() > 1) 1726d2e9b46Snicm tty_create_log(); 173cb19d99cSnicm if (pledge("stdio rpath wpath cpath fattr unix getpw recvfd proc exec " 174cb19d99cSnicm "tty ps", NULL) != 0) 1754e7a7adeSnicm fatal("pledge failed"); 1764e7a7adeSnicm 177ae69181dSnicm RB_INIT(&windows); 1783e0f2533Snicm RB_INIT(&all_window_panes); 17982873134Snicm TAILQ_INIT(&clients); 18059996dc3Snicm RB_INIT(&sessions); 18106440b28Snicm RB_INIT(&session_groups); 182311827fbSnicm key_bindings_init(); 183311827fbSnicm 1848c1ade38Snicm gettimeofday(&start_time, NULL); 185311827fbSnicm 1867724d0b0Snicm server_fd = server_create_socket(); 187d53cf33dSnicm if (server_fd == -1) 188d53cf33dSnicm fatal("couldn't create socket"); 189d53cf33dSnicm server_update_socket(); 19089654e7cSnicm server_client_create(pair[1]); 191311827fbSnicm 1925c705c36Snicm if (lockfd >= 0) { 193549634dfSnicm unlink(lockfile); 1947d053cf9Snicm free(lockfile); 195549634dfSnicm close(lockfd); 1965c705c36Snicm } 197549634dfSnicm 19884cce0efSnicm start_cfg(); 199175d36ccSnicm 200a06e463cSnicm server_add_accept(0); 2017724d0b0Snicm 2025b8ac713Snicm proc_loop(server_proc, server_loop); 2031a432fefSnicm 2041a432fefSnicm LIST_FOREACH(job, &all_jobs, entry) { 2051a432fefSnicm if (job->pid != -1) 2061a432fefSnicm kill(job->pid, SIGTERM); 2071a432fefSnicm } 2081a432fefSnicm 209179ef399Snicm status_prompt_save_history(); 2107724d0b0Snicm exit(0); 211311827fbSnicm } 212311827fbSnicm 2135b8ac713Snicm /* Server loop callback. */ 2149883b791Snicm static int 2157724d0b0Snicm server_loop(void) 216311827fbSnicm { 2175b8ac713Snicm struct client *c; 218765b9a58Snicm u_int items; 219765b9a58Snicm 220765b9a58Snicm do { 221765b9a58Snicm items = cmdq_next(NULL); 2226a2dc005Snicm TAILQ_FOREACH(c, &clients, entry) { 2236a2dc005Snicm if (c->flags & CLIENT_IDENTIFIED) 224765b9a58Snicm items += cmdq_next(c); 2256a2dc005Snicm } 226765b9a58Snicm } while (items != 0); 227311827fbSnicm 22889654e7cSnicm server_client_loop(); 22930da262fSnicm 230d89252e5Snicm if (!options_get_number(global_options, "exit-unattached")) { 23159996dc3Snicm if (!RB_EMPTY(&sessions)) 23230da262fSnicm return (0); 23330da262fSnicm } 2347d5939e2Snicm 23582873134Snicm TAILQ_FOREACH(c, &clients, entry) { 23682873134Snicm if (c->session != NULL) 2377d5939e2Snicm return (0); 2387d5939e2Snicm } 2397d5939e2Snicm 2407d5939e2Snicm /* 2417d5939e2Snicm * No attached clients therefore want to exit - flush any waiting 2427d5939e2Snicm * clients but don't actually exit until they've gone. 2437d5939e2Snicm */ 2447d5939e2Snicm cmd_wait_for_flush(); 24582873134Snicm if (!TAILQ_EMPTY(&clients)) 24630da262fSnicm return (0); 2477d5939e2Snicm 24830da262fSnicm return (1); 249311827fbSnicm } 250311827fbSnicm 2514d9325ceSnicm /* Exit the server by killing all clients and windows. */ 2529883b791Snicm static void 2534d9325ceSnicm server_send_exit(void) 254311827fbSnicm { 25582873134Snicm struct client *c, *c1; 25682873134Snicm struct session *s, *s1; 257311827fbSnicm 2587d5939e2Snicm cmd_wait_for_flush(); 2597d5939e2Snicm 26082873134Snicm TAILQ_FOREACH_SAFE(c, &clients, entry, c1) { 2615b8ac713Snicm if (c->flags & CLIENT_SUSPENDED) 2627724d0b0Snicm server_client_lost(c); 2637724d0b0Snicm else 2645b8ac713Snicm proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0); 2657724d0b0Snicm c->session = NULL; 2668148c7feSnicm } 267311827fbSnicm 26882873134Snicm RB_FOREACH_SAFE(s, sessions, &sessions, s1) 269bc4816c6Snicm session_destroy(s, __func__); 270311827fbSnicm } 271311827fbSnicm 2727724d0b0Snicm /* Update socket execute permissions based on whether sessions are attached. */ 27337dfd443Snicm void 2747724d0b0Snicm server_update_socket(void) 2757724d0b0Snicm { 2767724d0b0Snicm struct session *s; 2777724d0b0Snicm static int last = -1; 2786d9987f5Snicm int n, mode; 2796d9987f5Snicm struct stat sb; 2807724d0b0Snicm 2817724d0b0Snicm n = 0; 28259996dc3Snicm RB_FOREACH(s, sessions, &sessions) { 28359996dc3Snicm if (!(s->flags & SESSION_UNATTACHED)) { 2847724d0b0Snicm n++; 2857724d0b0Snicm break; 2867724d0b0Snicm } 2877724d0b0Snicm } 2887724d0b0Snicm 2897724d0b0Snicm if (n != last) { 2907724d0b0Snicm last = n; 2916d9987f5Snicm 2926d9987f5Snicm if (stat(socket_path, &sb) != 0) 2936d9987f5Snicm return; 294d61e0664Ssemarie mode = sb.st_mode & ACCESSPERMS; 2956d9987f5Snicm if (n != 0) { 2966d9987f5Snicm if (mode & S_IRUSR) 2976d9987f5Snicm mode |= S_IXUSR; 2986d9987f5Snicm if (mode & S_IRGRP) 2996d9987f5Snicm mode |= S_IXGRP; 3006d9987f5Snicm if (mode & S_IROTH) 3016d9987f5Snicm mode |= S_IXOTH; 3026d9987f5Snicm } else 3036d9987f5Snicm mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 3046d9987f5Snicm chmod(socket_path, mode); 3057724d0b0Snicm } 3067724d0b0Snicm } 3077724d0b0Snicm 3087724d0b0Snicm /* Callback for server socket. */ 3099883b791Snicm static void 310d0e2e7f1Snicm server_accept(int fd, short events, __unused void *data) 3117724d0b0Snicm { 3127724d0b0Snicm struct sockaddr_storage sa; 3137724d0b0Snicm socklen_t slen = sizeof sa; 3147724d0b0Snicm int newfd; 3157724d0b0Snicm 316a06e463cSnicm server_add_accept(0); 3177724d0b0Snicm if (!(events & EV_READ)) 3187724d0b0Snicm return; 3197724d0b0Snicm 3207724d0b0Snicm newfd = accept(fd, (struct sockaddr *) &sa, &slen); 3217724d0b0Snicm if (newfd == -1) { 3227724d0b0Snicm if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) 3237724d0b0Snicm return; 324a06e463cSnicm if (errno == ENFILE || errno == EMFILE) { 325a06e463cSnicm /* Delete and don't try again for 1 second. */ 326a06e463cSnicm server_add_accept(1); 327a06e463cSnicm return; 328a06e463cSnicm } 3297724d0b0Snicm fatal("accept failed"); 3307724d0b0Snicm } 3314d9325ceSnicm if (server_exit) { 3327724d0b0Snicm close(newfd); 3337724d0b0Snicm return; 3347724d0b0Snicm } 3357724d0b0Snicm server_client_create(newfd); 3367724d0b0Snicm } 3377724d0b0Snicm 338a06e463cSnicm /* 339a06e463cSnicm * Add accept event. If timeout is nonzero, add as a timeout instead of a read 340a06e463cSnicm * event - used to backoff when running out of file descriptors. 341a06e463cSnicm */ 342a06e463cSnicm void 343a06e463cSnicm server_add_accept(int timeout) 344a06e463cSnicm { 345a06e463cSnicm struct timeval tv = { timeout, 0 }; 346a06e463cSnicm 347a06e463cSnicm if (event_initialized(&server_ev_accept)) 348a06e463cSnicm event_del(&server_ev_accept); 349a06e463cSnicm 350a06e463cSnicm if (timeout == 0) { 3515b8ac713Snicm event_set(&server_ev_accept, server_fd, EV_READ, server_accept, 3525b8ac713Snicm NULL); 353a06e463cSnicm event_add(&server_ev_accept, NULL); 354a06e463cSnicm } else { 3555b8ac713Snicm event_set(&server_ev_accept, server_fd, EV_TIMEOUT, 3565b8ac713Snicm server_accept, NULL); 357a06e463cSnicm event_add(&server_ev_accept, &tv); 358a06e463cSnicm } 359a06e463cSnicm } 360a06e463cSnicm 3617724d0b0Snicm /* Signal handler. */ 3629883b791Snicm static void 3635b8ac713Snicm server_signal(int sig) 3647724d0b0Snicm { 365d53cf33dSnicm int fd; 3665235cd7fSnicm 367bc4816c6Snicm log_debug("%s: %s", __func__, strsignal(sig)); 3687724d0b0Snicm switch (sig) { 3697724d0b0Snicm case SIGTERM: 3704d9325ceSnicm server_exit = 1; 3714d9325ceSnicm server_send_exit(); 3727724d0b0Snicm break; 3737724d0b0Snicm case SIGCHLD: 3747724d0b0Snicm server_child_signal(); 3757724d0b0Snicm break; 3767724d0b0Snicm case SIGUSR1: 3777724d0b0Snicm event_del(&server_ev_accept); 378d53cf33dSnicm fd = server_create_socket(); 379d53cf33dSnicm if (fd != -1) { 3807724d0b0Snicm close(server_fd); 381d53cf33dSnicm server_fd = fd; 382d53cf33dSnicm server_update_socket(); 383d53cf33dSnicm } 384a06e463cSnicm server_add_accept(0); 3857724d0b0Snicm break; 38679c9b201Snicm case SIGUSR2: 38779c9b201Snicm proc_toggle_log(server_proc); 38879c9b201Snicm break; 3897724d0b0Snicm } 3907724d0b0Snicm } 3917724d0b0Snicm 3927724d0b0Snicm /* Handle SIGCHLD. */ 3939883b791Snicm static void 3947724d0b0Snicm server_child_signal(void) 3957724d0b0Snicm { 3967724d0b0Snicm int status; 3977724d0b0Snicm pid_t pid; 3987724d0b0Snicm 3997724d0b0Snicm for (;;) { 4007724d0b0Snicm switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) { 4017724d0b0Snicm case -1: 4027724d0b0Snicm if (errno == ECHILD) 4037724d0b0Snicm return; 4047724d0b0Snicm fatal("waitpid failed"); 4057724d0b0Snicm case 0: 4067724d0b0Snicm return; 4077724d0b0Snicm } 4087724d0b0Snicm if (WIFSTOPPED(status)) 4097724d0b0Snicm server_child_stopped(pid, status); 410a236b623Snicm else if (WIFEXITED(status) || WIFSIGNALED(status)) 4117724d0b0Snicm server_child_exited(pid, status); 4127724d0b0Snicm } 4137724d0b0Snicm } 4147724d0b0Snicm 4157724d0b0Snicm /* Handle exited children. */ 4169883b791Snicm static void 4177724d0b0Snicm server_child_exited(pid_t pid, int status) 418311827fbSnicm { 419ae69181dSnicm struct window *w, *w1; 42089654e7cSnicm struct window_pane *wp; 4217724d0b0Snicm struct job *job; 4227724d0b0Snicm 423ae69181dSnicm RB_FOREACH_SAFE(w, windows, &windows, w1) { 4247724d0b0Snicm TAILQ_FOREACH(wp, &w->panes, entry) { 4257724d0b0Snicm if (wp->pid == pid) { 4263e459475Snicm wp->status = status; 427*514fd64dSnicm wp->flags |= PANE_STATUSREADY; 428f35e5f52Snicm 429f35e5f52Snicm log_debug("%%%u exited", wp->id); 430f35e5f52Snicm wp->flags |= PANE_EXITED; 431f35e5f52Snicm 432f35e5f52Snicm if (window_pane_destroy_ready(wp)) 4334fc586aaSnicm server_destroy_pane(wp, 1); 4347c6e570cSnicm break; 4357724d0b0Snicm } 4367724d0b0Snicm } 4377724d0b0Snicm } 4387724d0b0Snicm 4391a432fefSnicm LIST_FOREACH(job, &all_jobs, entry) { 4407724d0b0Snicm if (pid == job->pid) { 44124abd014Snicm job_died(job, status); /* might free job */ 44224abd014Snicm break; 4437724d0b0Snicm } 4447724d0b0Snicm } 4457724d0b0Snicm } 4467724d0b0Snicm 4477724d0b0Snicm /* Handle stopped children. */ 4489883b791Snicm static void 4497724d0b0Snicm server_child_stopped(pid_t pid, int status) 4507724d0b0Snicm { 4517724d0b0Snicm struct window *w; 4527724d0b0Snicm struct window_pane *wp; 4537724d0b0Snicm 4547724d0b0Snicm if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) 4557724d0b0Snicm return; 4567724d0b0Snicm 457ae69181dSnicm RB_FOREACH(w, windows, &windows) { 4587724d0b0Snicm TAILQ_FOREACH(wp, &w->panes, entry) { 4597724d0b0Snicm if (wp->pid == pid) { 4607724d0b0Snicm if (killpg(pid, SIGCONT) != 0) 4617724d0b0Snicm kill(pid, SIGCONT); 4627724d0b0Snicm } 4637724d0b0Snicm } 4647724d0b0Snicm } 4657724d0b0Snicm } 466