File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / server.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (7 years, 9 months ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>