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