"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/server.c" (10 Jun 2021, 11451 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* $OpenBSD$ */
    2 
    3 /*
    4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
    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>
   28 #include <signal.h>
   29 #include <stdio.h>
   30 #include <stdlib.h>
   31 #include <string.h>
   32 #include <termios.h>
   33 #include <time.h>
   34 #include <unistd.h>
   35 
   36 #include "tmux.h"
   37 
   38 /*
   39  * Main server functions.
   40  */
   41 
   42 struct clients       clients;
   43 
   44 struct tmuxproc     *server_proc;
   45 static int       server_fd = -1;
   46 static uint64_t      server_client_flags;
   47 static int       server_exit;
   48 static struct event  server_ev_accept;
   49 static struct event  server_ev_tidy;
   50 
   51 struct cmd_find_state    marked_pane;
   52 
   53 static u_int         message_next;
   54 struct message_list  message_log;
   55 
   56 static int  server_loop(void);
   57 static void server_send_exit(void);
   58 static void server_accept(int, short, void *);
   59 static void server_signal(int);
   60 static void server_child_signal(void);
   61 static void server_child_exited(pid_t, int);
   62 static void server_child_stopped(pid_t, int);
   63 
   64 /* Set marked pane. */
   65 void
   66 server_set_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
   67 {
   68     cmd_find_clear_state(&marked_pane, 0);
   69     marked_pane.s = s;
   70     marked_pane.wl = wl;
   71     marked_pane.w = wl->window;
   72     marked_pane.wp = wp;
   73 }
   74 
   75 /* Clear marked pane. */
   76 void
   77 server_clear_marked(void)
   78 {
   79     cmd_find_clear_state(&marked_pane, 0);
   80 }
   81 
   82 /* Is this the marked pane? */
   83 int
   84 server_is_marked(struct session *s, struct winlink *wl, struct window_pane *wp)
   85 {
   86     if (s == NULL || wl == NULL || wp == NULL)
   87         return (0);
   88     if (marked_pane.s != s || marked_pane.wl != wl)
   89         return (0);
   90     if (marked_pane.wp != wp)
   91         return (0);
   92     return (server_check_marked());
   93 }
   94 
   95 /* Check if the marked pane is still valid. */
   96 int
   97 server_check_marked(void)
   98 {
   99     return (cmd_find_valid_state(&marked_pane));
  100 }
  101 
  102 /* Create server socket. */
  103 static int
  104 server_create_socket(int flags, char **cause)
  105 {
  106     struct sockaddr_un  sa;
  107     size_t          size;
  108     mode_t          mask;
  109     int         fd, saved_errno;
  110 
  111     memset(&sa, 0, sizeof sa);
  112     sa.sun_family = AF_UNIX;
  113     size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
  114     if (size >= sizeof sa.sun_path) {
  115         errno = ENAMETOOLONG;
  116         goto fail;
  117     }
  118     unlink(sa.sun_path);
  119 
  120     if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
  121         goto fail;
  122 
  123     if (flags & CLIENT_DEFAULTSOCKET)
  124         mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
  125     else
  126         mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
  127     if (bind(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
  128         saved_errno = errno;
  129         close(fd);
  130         errno = saved_errno;
  131         goto fail;
  132     }
  133     umask(mask);
  134 
  135     if (listen(fd, 128) == -1) {
  136         saved_errno = errno;
  137         close(fd);
  138         errno = saved_errno;
  139         goto fail;
  140     }
  141     setblocking(fd, 0);
  142 
  143     return (fd);
  144 
  145 fail:
  146     if (cause != NULL) {
  147         xasprintf(cause, "error creating %s (%s)", socket_path,
  148             strerror(errno));
  149     }
  150     return (-1);
  151 }
  152 
  153 /* Tidy up every hour. */
  154 static void
  155 server_tidy_event(__unused int fd, __unused short events, __unused void *data)
  156 {
  157     struct timeval  tv = { .tv_sec = 3600 };
  158     uint64_t        t = get_timer();
  159 
  160     format_tidy_jobs();
  161 
  162 #ifdef HAVE_MALLOC_TRIM
  163     malloc_trim(0);
  164 #endif
  165 
  166     log_debug("%s: took %llu milliseconds", __func__,
  167         (unsigned long long)(get_timer() - t));
  168     evtimer_add(&server_ev_tidy, &tv);
  169 }
  170 
  171 /* Fork new server. */
  172 int
  173 server_start(struct tmuxproc *client, int flags, struct event_base *base,
  174     int lockfd, char *lockfile)
  175 {
  176     int      fd;
  177     sigset_t     set, oldset;
  178     struct client   *c = NULL;
  179     char        *cause = NULL;
  180     struct timeval   tv = { .tv_sec = 3600 };
  181 
  182     sigfillset(&set);
  183     sigprocmask(SIG_BLOCK, &set, &oldset);
  184 
  185     if (~flags & CLIENT_NOFORK) {
  186         if (proc_fork_and_daemon(&fd) != 0) {
  187             sigprocmask(SIG_SETMASK, &oldset, NULL);
  188             return (fd);
  189         }
  190     }
  191     proc_clear_signals(client, 0);
  192     server_client_flags = flags;
  193 
  194     if (event_reinit(base) != 0)
  195         fatalx("event_reinit failed");
  196     server_proc = proc_start("server");
  197 
  198     proc_set_signals(server_proc, server_signal);
  199     sigprocmask(SIG_SETMASK, &oldset, NULL);
  200 
  201     if (log_get_level() > 1)
  202         tty_create_log();
  203     if (pledge("stdio rpath wpath cpath fattr unix getpw recvfd proc exec "
  204         "tty ps", NULL) != 0)
  205         fatal("pledge failed");
  206 
  207     input_key_build();
  208     RB_INIT(&windows);
  209     RB_INIT(&all_window_panes);
  210     TAILQ_INIT(&clients);
  211     RB_INIT(&sessions);
  212     key_bindings_init();
  213     TAILQ_INIT(&message_log);
  214 
  215     gettimeofday(&start_time, NULL);
  216 
  217     server_fd = server_create_socket(flags, &cause);
  218     if (server_fd != -1)
  219         server_update_socket();
  220     if (~flags & CLIENT_NOFORK)
  221         c = server_client_create(fd);
  222     else
  223         options_set_number(global_options, "exit-empty", 0);
  224 
  225     if (lockfd >= 0) {
  226         unlink(lockfile);
  227         free(lockfile);
  228         close(lockfd);
  229     }
  230 
  231     if (cause != NULL) {
  232         if (c != NULL) {
  233             cmdq_append(c, cmdq_get_error(cause));
  234             c->flags |= CLIENT_EXIT;
  235         }
  236         free(cause);
  237     }
  238 
  239     evtimer_set(&server_ev_tidy, server_tidy_event, NULL);
  240     evtimer_add(&server_ev_tidy, &tv);
  241 
  242     server_add_accept(0);
  243     proc_loop(server_proc, server_loop);
  244 
  245     job_kill_all();
  246     status_prompt_save_history();
  247 
  248     exit(0);
  249 }
  250 
  251 /* Server loop callback. */
  252 static int
  253 server_loop(void)
  254 {
  255     struct client   *c;
  256     u_int        items;
  257 
  258     do {
  259         items = cmdq_next(NULL);
  260         TAILQ_FOREACH(c, &clients, entry) {
  261             if (c->flags & CLIENT_IDENTIFIED)
  262                 items += cmdq_next(c);
  263         }
  264     } while (items != 0);
  265 
  266     server_client_loop();
  267 
  268     if (!options_get_number(global_options, "exit-empty") && !server_exit)
  269         return (0);
  270 
  271     if (!options_get_number(global_options, "exit-unattached")) {
  272         if (!RB_EMPTY(&sessions))
  273             return (0);
  274     }
  275 
  276     TAILQ_FOREACH(c, &clients, entry) {
  277         if (c->session != NULL)
  278             return (0);
  279     }
  280 
  281     /*
  282      * No attached clients therefore want to exit - flush any waiting
  283      * clients but don't actually exit until they've gone.
  284      */
  285     cmd_wait_for_flush();
  286     if (!TAILQ_EMPTY(&clients))
  287         return (0);
  288 
  289     if (job_still_running())
  290         return (0);
  291 
  292     return (1);
  293 }
  294 
  295 /* Exit the server by killing all clients and windows. */
  296 static void
  297 server_send_exit(void)
  298 {
  299     struct client   *c, *c1;
  300     struct session  *s, *s1;
  301 
  302     cmd_wait_for_flush();
  303 
  304     TAILQ_FOREACH_SAFE(c, &clients, entry, c1) {
  305         if (c->flags & CLIENT_SUSPENDED)
  306             server_client_lost(c);
  307         else {
  308             c->flags |= CLIENT_EXIT;
  309             c->exit_type = CLIENT_EXIT_SHUTDOWN;
  310         }
  311         c->session = NULL;
  312     }
  313 
  314     RB_FOREACH_SAFE(s, sessions, &sessions, s1)
  315         session_destroy(s, 1, __func__);
  316 }
  317 
  318 /* Update socket execute permissions based on whether sessions are attached. */
  319 void
  320 server_update_socket(void)
  321 {
  322     struct session  *s;
  323     static int   last = -1;
  324     int      n, mode;
  325     struct stat      sb;
  326 
  327     n = 0;
  328     RB_FOREACH(s, sessions, &sessions) {
  329         if (s->attached != 0) {
  330             n++;
  331             break;
  332         }
  333     }
  334 
  335     if (n != last) {
  336         last = n;
  337 
  338         if (stat(socket_path, &sb) != 0)
  339             return;
  340         mode = sb.st_mode & ACCESSPERMS;
  341         if (n != 0) {
  342             if (mode & S_IRUSR)
  343                 mode |= S_IXUSR;
  344             if (mode & S_IRGRP)
  345                 mode |= S_IXGRP;
  346             if (mode & S_IROTH)
  347                 mode |= S_IXOTH;
  348         } else
  349             mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
  350         chmod(socket_path, mode);
  351     }
  352 }
  353 
  354 /* Callback for server socket. */
  355 static void
  356 server_accept(int fd, short events, __unused void *data)
  357 {
  358     struct sockaddr_storage sa;
  359     socklen_t       slen = sizeof sa;
  360     int         newfd;
  361 
  362     server_add_accept(0);
  363     if (!(events & EV_READ))
  364         return;
  365 
  366     newfd = accept(fd, (struct sockaddr *) &sa, &slen);
  367     if (newfd == -1) {
  368         if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
  369             return;
  370         if (errno == ENFILE || errno == EMFILE) {
  371             /* Delete and don't try again for 1 second. */
  372             server_add_accept(1);
  373             return;
  374         }
  375         fatal("accept failed");
  376     }
  377     if (server_exit) {
  378         close(newfd);
  379         return;
  380     }
  381     server_client_create(newfd);
  382 }
  383 
  384 /*
  385  * Add accept event. If timeout is nonzero, add as a timeout instead of a read
  386  * event - used to backoff when running out of file descriptors.
  387  */
  388 void
  389 server_add_accept(int timeout)
  390 {
  391     struct timeval tv = { timeout, 0 };
  392 
  393     if (server_fd == -1)
  394         return;
  395 
  396     if (event_initialized(&server_ev_accept))
  397         event_del(&server_ev_accept);
  398 
  399     if (timeout == 0) {
  400         event_set(&server_ev_accept, server_fd, EV_READ, server_accept,
  401             NULL);
  402         event_add(&server_ev_accept, NULL);
  403     } else {
  404         event_set(&server_ev_accept, server_fd, EV_TIMEOUT,
  405             server_accept, NULL);
  406         event_add(&server_ev_accept, &tv);
  407     }
  408 }
  409 
  410 /* Signal handler. */
  411 static void
  412 server_signal(int sig)
  413 {
  414     int fd;
  415 
  416     log_debug("%s: %s", __func__, strsignal(sig));
  417     switch (sig) {
  418     case SIGINT:
  419     case SIGTERM:
  420         server_exit = 1;
  421         server_send_exit();
  422         break;
  423     case SIGCHLD:
  424         server_child_signal();
  425         break;
  426     case SIGUSR1:
  427         event_del(&server_ev_accept);
  428         fd = server_create_socket(server_client_flags, NULL);
  429         if (fd != -1) {
  430             close(server_fd);
  431             server_fd = fd;
  432             server_update_socket();
  433         }
  434         server_add_accept(0);
  435         break;
  436     case SIGUSR2:
  437         proc_toggle_log(server_proc);
  438         break;
  439     }
  440 }
  441 
  442 /* Handle SIGCHLD. */
  443 static void
  444 server_child_signal(void)
  445 {
  446     int  status;
  447     pid_t    pid;
  448 
  449     for (;;) {
  450         switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
  451         case -1:
  452             if (errno == ECHILD)
  453                 return;
  454             fatal("waitpid failed");
  455         case 0:
  456             return;
  457         }
  458         if (WIFSTOPPED(status))
  459             server_child_stopped(pid, status);
  460         else if (WIFEXITED(status) || WIFSIGNALED(status))
  461             server_child_exited(pid, status);
  462     }
  463 }
  464 
  465 /* Handle exited children. */
  466 static void
  467 server_child_exited(pid_t pid, int status)
  468 {
  469     struct window       *w, *w1;
  470     struct window_pane  *wp;
  471 
  472     RB_FOREACH_SAFE(w, windows, &windows, w1) {
  473         TAILQ_FOREACH(wp, &w->panes, entry) {
  474             if (wp->pid == pid) {
  475                 wp->status = status;
  476                 wp->flags |= PANE_STATUSREADY;
  477 
  478                 log_debug("%%%u exited", wp->id);
  479                 wp->flags |= PANE_EXITED;
  480 
  481                 if (window_pane_destroy_ready(wp))
  482                     server_destroy_pane(wp, 1);
  483                 break;
  484             }
  485         }
  486     }
  487     job_check_died(pid, status);
  488 }
  489 
  490 /* Handle stopped children. */
  491 static void
  492 server_child_stopped(pid_t pid, int status)
  493 {
  494     struct window       *w;
  495     struct window_pane  *wp;
  496 
  497     if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
  498         return;
  499 
  500     RB_FOREACH(w, windows, &windows) {
  501         TAILQ_FOREACH(wp, &w->panes, entry) {
  502             if (wp->pid == pid) {
  503                 if (killpg(pid, SIGCONT) != 0)
  504                     kill(pid, SIGCONT);
  505             }
  506         }
  507     }
  508     job_check_died(pid, status);
  509 }
  510 
  511 /* Add to message log. */
  512 void
  513 server_add_message(const char *fmt, ...)
  514 {
  515     struct message_entry    *msg, *msg1;
  516     char            *s;
  517     va_list          ap;
  518     u_int            limit;
  519 
  520     va_start(ap, fmt);
  521     xvasprintf(&s, fmt, ap);
  522     va_end(ap);
  523 
  524     log_debug("message: %s", s);
  525 
  526     msg = xcalloc(1, sizeof *msg);
  527     gettimeofday(&msg->msg_time, NULL);
  528     msg->msg_num = message_next++;
  529     msg->msg = s;
  530     TAILQ_INSERT_TAIL(&message_log, msg, entry);
  531 
  532     limit = options_get_number(global_options, "message-limit");
  533     TAILQ_FOREACH_SAFE(msg, &message_log, entry, msg1) {
  534         if (msg->msg_num + limit >= message_next)
  535             break;
  536         free(msg->msg);
  537         TAILQ_REMOVE(&message_log, msg, entry);
  538         free(msg);
  539     }
  540 }