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