xref: /minix/external/bsd/tmux/dist/server.c (revision 27852ebe)
1 /* Id */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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 <syslog.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 
44 /* Client list. */
45 struct clients	 clients;
46 struct clients	 dead_clients;
47 
48 int		 server_fd;
49 int		 server_shutdown;
50 struct event	 server_ev_accept;
51 struct event	 server_ev_second;
52 
53 struct paste_stack global_buffers;
54 
55 int		 server_create_socket(void);
56 void		 server_loop(void);
57 int		 server_should_shutdown(void);
58 void		 server_send_shutdown(void);
59 void		 server_clean_dead(void);
60 void		 server_accept_callback(int, short, void *);
61 void		 server_signal_callback(int, short, void *);
62 void		 server_child_signal(void);
63 void		 server_child_exited(pid_t, int);
64 void		 server_child_stopped(pid_t, int);
65 void		 server_second_callback(int, short, void *);
66 void		 server_lock_server(void);
67 void		 server_lock_sessions(void);
68 
69 /* Create server socket. */
70 int
server_create_socket(void)71 server_create_socket(void)
72 {
73 	struct sockaddr_un	sa;
74 	size_t			size;
75 	mode_t			mask;
76 	int			fd;
77 
78 	memset(&sa, 0, sizeof sa);
79 	sa.sun_family = AF_UNIX;
80 	size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
81 	if (size >= sizeof sa.sun_path) {
82 		errno = ENAMETOOLONG;
83 		fatal("socket failed");
84 	}
85 	unlink(sa.sun_path);
86 
87 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
88 		fatal("socket failed");
89 
90 	mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
91 	if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
92 		fatal("bind failed");
93 	umask(mask);
94 
95 	if (listen(fd, 16) == -1)
96 		fatal("listen failed");
97 	setblocking(fd, 0);
98 
99 	server_update_socket();
100 
101 	return (fd);
102 }
103 
104 /* Fork new server. */
105 int
server_start(int lockfd,char * lockfile)106 server_start(int lockfd, char *lockfile)
107 {
108 	int	 	 pair[2];
109 	struct timeval	 tv;
110 	char		*cause;
111 
112 	/* The first client is special and gets a socketpair; create it. */
113 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
114 		fatal("socketpair failed");
115 
116 	switch (fork()) {
117 	case -1:
118 		fatal("fork failed");
119 	case 0:
120 		break;
121 	default:
122 		close(pair[1]);
123 		return (pair[0]);
124 	}
125 	close(pair[0]);
126 
127 	/*
128 	 * Must daemonise before loading configuration as the PID changes so
129 	 * $TMUX would be wrong for sessions created in the config file.
130 	 */
131 	if (daemon(1, 0) != 0)
132 		fatal("daemon failed");
133 
134 	/* event_init() was called in our parent, need to reinit. */
135 	if (event_reinit(ev_base) != 0)
136 		fatal("event_reinit failed");
137 	clear_signals(0);
138 
139 	logfile("server");
140 	log_debug("server started, pid %ld", (long) getpid());
141 
142 	ARRAY_INIT(&windows);
143 	RB_INIT(&all_window_panes);
144 	ARRAY_INIT(&clients);
145 	ARRAY_INIT(&dead_clients);
146 	RB_INIT(&sessions);
147 	RB_INIT(&dead_sessions);
148 	TAILQ_INIT(&session_groups);
149 	ARRAY_INIT(&global_buffers);
150 	mode_key_init_trees();
151 	key_bindings_init();
152 	utf8_build();
153 
154 	start_time = time(NULL);
155 	log_debug("socket path %s", socket_path);
156 #ifdef HAVE_SETPROCTITLE
157 	setproctitle("server (%s)", socket_path);
158 #endif
159 
160 	server_fd = server_create_socket();
161 	server_client_create(pair[1]);
162 
163 	unlink(lockfile);
164 	free(lockfile);
165 	close(lockfd);
166 
167 	cfg_cmd_q = cmdq_new(NULL);
168 	cfg_cmd_q->emptyfn = cfg_default_done;
169 	cfg_finished = 0;
170 	cfg_references = 1;
171 	ARRAY_INIT(&cfg_causes);
172 	cfg_client = ARRAY_FIRST(&clients);
173 	if (cfg_client != NULL)
174 		cfg_client->references++;
175 
176 	if (access(TMUX_CONF, R_OK) == 0) {
177 		if (load_cfg(TMUX_CONF, cfg_cmd_q, &cause) == -1) {
178 			xasprintf(&cause, "%s: %s", TMUX_CONF, cause);
179 			ARRAY_ADD(&cfg_causes, cause);
180 		}
181 	} else if (errno != ENOENT) {
182 		xasprintf(&cause, "%s: %s", TMUX_CONF, strerror(errno));
183 		ARRAY_ADD(&cfg_causes, cause);
184 	}
185 	if (cfg_file != NULL) {
186 		if (load_cfg(cfg_file, cfg_cmd_q, &cause) == -1) {
187 			xasprintf(&cause, "%s: %s", cfg_file, cause);
188 			ARRAY_ADD(&cfg_causes, cause);
189 		}
190 	}
191 	cmdq_continue(cfg_cmd_q);
192 
193 	server_add_accept(0);
194 
195 	memset(&tv, 0, sizeof tv);
196 	tv.tv_sec = 1;
197 	evtimer_set(&server_ev_second, server_second_callback, NULL);
198 	evtimer_add(&server_ev_second, &tv);
199 
200 	set_signals(server_signal_callback);
201 	server_loop();
202 	exit(0);
203 }
204 
205 /* Main server loop. */
206 void
server_loop(void)207 server_loop(void)
208 {
209 	while (!server_should_shutdown()) {
210 		event_loop(EVLOOP_ONCE);
211 
212 		server_window_loop();
213 		server_client_loop();
214 
215 		key_bindings_clean();
216 		server_clean_dead();
217 	}
218 }
219 
220 /* Check if the server should be shutting down (no more clients or sessions). */
221 int
server_should_shutdown(void)222 server_should_shutdown(void)
223 {
224 	u_int	i;
225 
226 	if (!options_get_number(&global_options, "exit-unattached")) {
227 		if (!RB_EMPTY(&sessions))
228 			return (0);
229 	}
230 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
231 		if (ARRAY_ITEM(&clients, i) != NULL)
232 			return (0);
233 	}
234 	return (1);
235 }
236 
237 /* Shutdown the server by killing all clients and windows. */
238 void
server_send_shutdown(void)239 server_send_shutdown(void)
240 {
241 	struct client	*c;
242 	struct session	*s, *next_s;
243 	u_int		 i;
244 
245 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
246 		c = ARRAY_ITEM(&clients, i);
247 		if (c != NULL) {
248 			if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
249 				server_client_lost(c);
250 			else
251 				server_write_client(c, MSG_SHUTDOWN, NULL, 0);
252 			c->session = NULL;
253 		}
254 	}
255 
256 	s = RB_MIN(sessions, &sessions);
257 	while (s != NULL) {
258 		next_s = RB_NEXT(sessions, &sessions, s);
259 		session_destroy(s);
260 		s = next_s;
261 	}
262 }
263 
264 /* Free dead, unreferenced clients and sessions. */
265 void
server_clean_dead(void)266 server_clean_dead(void)
267 {
268 	struct session	*s, *next_s;
269 	struct client	*c;
270 	u_int		 i;
271 
272 	s = RB_MIN(sessions, &dead_sessions);
273 	while (s != NULL) {
274 		next_s = RB_NEXT(sessions, &dead_sessions, s);
275 		if (s->references == 0) {
276 			RB_REMOVE(sessions, &dead_sessions, s);
277 			free(s->name);
278 			free(s);
279 		}
280 		s = next_s;
281 	}
282 
283 	for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
284 		c = ARRAY_ITEM(&dead_clients, i);
285 		if (c == NULL || c->references != 0)
286 			continue;
287 		ARRAY_SET(&dead_clients, i, NULL);
288 		free(c);
289 	}
290 }
291 
292 /* Update socket execute permissions based on whether sessions are attached. */
293 void
server_update_socket(void)294 server_update_socket(void)
295 {
296 	struct session	*s;
297 	static int	 last = -1;
298 	int		 n, mode;
299 	struct stat      sb;
300 
301 	n = 0;
302 	RB_FOREACH(s, sessions, &sessions) {
303 		if (!(s->flags & SESSION_UNATTACHED)) {
304 			n++;
305 			break;
306 		}
307 	}
308 
309 	if (n != last) {
310 		last = n;
311 
312 		if (stat(socket_path, &sb) != 0)
313 			return;
314 		mode = sb.st_mode;
315 		if (n != 0) {
316 			if (mode & S_IRUSR)
317 				mode |= S_IXUSR;
318 			if (mode & S_IRGRP)
319 				mode |= S_IXGRP;
320 			if (mode & S_IROTH)
321 				mode |= S_IXOTH;
322 		} else
323 			mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
324 		chmod(socket_path, mode);
325 	}
326 }
327 
328 /* Callback for server socket. */
329 void
server_accept_callback(int fd,short events,unused void * data)330 server_accept_callback(int fd, short events, unused void *data)
331 {
332 	struct sockaddr_storage	sa;
333 	socklen_t		slen = sizeof sa;
334 	int			newfd;
335 
336 	server_add_accept(0);
337 	if (!(events & EV_READ))
338 		return;
339 
340 	newfd = accept(fd, (struct sockaddr *) &sa, &slen);
341 	if (newfd == -1) {
342 		if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
343 			return;
344 		if (errno == ENFILE || errno == EMFILE) {
345 			/* Delete and don't try again for 1 second. */
346 			server_add_accept(1);
347 			return;
348 		}
349 		fatal("accept failed");
350 	}
351 	if (server_shutdown) {
352 		close(newfd);
353 		return;
354 	}
355 	server_client_create(newfd);
356 }
357 
358 /*
359  * Add accept event. If timeout is nonzero, add as a timeout instead of a read
360  * event - used to backoff when running out of file descriptors.
361  */
362 void
server_add_accept(int timeout)363 server_add_accept(int timeout)
364 {
365 	struct timeval tv = { timeout, 0 };
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,
372 		    server_fd, EV_READ, server_accept_callback, NULL);
373 		event_add(&server_ev_accept, NULL);
374 	} else {
375 		event_set(&server_ev_accept,
376 		    server_fd, EV_TIMEOUT, server_accept_callback, NULL);
377 		event_add(&server_ev_accept, &tv);
378 	}
379 }
380 
381 /* Signal handler. */
382 void
server_signal_callback(int sig,unused short events,unused void * data)383 server_signal_callback(int sig, unused short events, unused void *data)
384 {
385 	switch (sig) {
386 	case SIGTERM:
387 		server_shutdown = 1;
388 		server_send_shutdown();
389 		break;
390 	case SIGCHLD:
391 		server_child_signal();
392 		break;
393 	case SIGUSR1:
394 		event_del(&server_ev_accept);
395 		close(server_fd);
396 		server_fd = server_create_socket();
397 		server_add_accept(0);
398 		break;
399 	}
400 }
401 
402 /* Handle SIGCHLD. */
403 void
server_child_signal(void)404 server_child_signal(void)
405 {
406 	int	 status;
407 	pid_t	 pid;
408 
409 	for (;;) {
410 		switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
411 		case -1:
412 			if (errno == ECHILD)
413 				return;
414 			fatal("waitpid failed");
415 		case 0:
416 			return;
417 		}
418 		if (WIFSTOPPED(status))
419 			server_child_stopped(pid, status);
420 		else if (WIFEXITED(status) || WIFSIGNALED(status))
421 			server_child_exited(pid, status);
422 	}
423 }
424 
425 /* Handle exited children. */
426 void
server_child_exited(pid_t pid,int status)427 server_child_exited(pid_t pid, int status)
428 {
429 	struct window		*w;
430 	struct window_pane	*wp;
431 	struct job		*job;
432 	u_int		 	 i;
433 
434 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
435 		if ((w = ARRAY_ITEM(&windows, i)) == NULL)
436 			continue;
437 		TAILQ_FOREACH(wp, &w->panes, entry) {
438 			if (wp->pid == pid) {
439 				server_destroy_pane(wp);
440 				break;
441 			}
442 		}
443 	}
444 
445 	LIST_FOREACH(job, &all_jobs, lentry) {
446 		if (pid == job->pid) {
447 			job_died(job, status);	/* might free job */
448 			break;
449 		}
450 	}
451 }
452 
453 /* Handle stopped children. */
454 void
server_child_stopped(pid_t pid,int status)455 server_child_stopped(pid_t pid, int status)
456 {
457 	struct window		*w;
458 	struct window_pane	*wp;
459 	u_int			 i;
460 
461 	if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
462 		return;
463 
464 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
465 		if ((w = ARRAY_ITEM(&windows, i)) == NULL)
466 			continue;
467 		TAILQ_FOREACH(wp, &w->panes, entry) {
468 			if (wp->pid == pid) {
469 				if (killpg(pid, SIGCONT) != 0)
470 					kill(pid, SIGCONT);
471 			}
472 		}
473 	}
474 }
475 
476 /* Handle once-per-second timer events. */
477 void
server_second_callback(unused int fd,unused short events,unused void * arg)478 server_second_callback(unused int fd, unused short events, unused void *arg)
479 {
480 	struct window		*w;
481 	struct window_pane	*wp;
482 	struct timeval		 tv;
483 	u_int		 	 i;
484 
485 	if (options_get_number(&global_s_options, "lock-server"))
486 		server_lock_server();
487 	else
488 		server_lock_sessions();
489 
490 	for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
491 		w = ARRAY_ITEM(&windows, i);
492 		if (w == NULL)
493 			continue;
494 
495 		TAILQ_FOREACH(wp, &w->panes, entry) {
496 			if (wp->mode != NULL && wp->mode->timer != NULL)
497 				wp->mode->timer(wp);
498 		}
499 	}
500 
501 	server_client_status_timer();
502 
503 	evtimer_del(&server_ev_second);
504 	memset(&tv, 0, sizeof tv);
505 	tv.tv_sec = 1;
506 	evtimer_add(&server_ev_second, &tv);
507 }
508 
509 /* Lock the server if ALL sessions have hit the time limit. */
510 void
server_lock_server(void)511 server_lock_server(void)
512 {
513 	struct session  *s;
514 	int		 timeout;
515 	time_t           t;
516 
517 	t = time(NULL);
518 	RB_FOREACH(s, sessions, &sessions) {
519 		if (s->flags & SESSION_UNATTACHED)
520 			continue;
521 		timeout = options_get_number(&s->options, "lock-after-time");
522 		if (timeout <= 0 || t <= s->activity_time.tv_sec + timeout)
523 			return;	/* not timed out */
524 	}
525 
526 	server_lock();
527 	recalculate_sizes();
528 }
529 
530 /* Lock any sessions which have timed out. */
531 void
server_lock_sessions(void)532 server_lock_sessions(void)
533 {
534 	struct session  *s;
535 	int		 timeout;
536 	time_t		 t;
537 
538 	t = time(NULL);
539 	RB_FOREACH(s, sessions, &sessions) {
540 		if (s->flags & SESSION_UNATTACHED)
541 			continue;
542 		timeout = options_get_number(&s->options, "lock-after-time");
543 		if (timeout > 0 && t > s->activity_time.tv_sec + timeout) {
544 			server_lock_session(s);
545 			recalculate_sizes();
546 		}
547 	}
548 }
549