summaryrefslogtreecommitdiffstats
path: root/ms
AgeCommit message (Expand)Author
2003-02-22add testUlf Möller
2003-02-21clean up MinGW build. MinGW make now supports the Windows path nameUlf Möller
2002-11-15WinCE patchesRichard Levitte
2002-11-14Make the Windows test scripts consistent in their echoingRichard Levitte
2002-06-27Use underscores instead of dashes in temporary file names.Richard Levitte
2002-05-19Fix Mingw32 asm build: use the UnixDr. Stephen Henson
2001-11-14Remove temporary filesRichard Levitte
2001-11-14Exclude .out filesRichard Levitte
2001-03-15It is a good thing to prepare the .def files.Richard Levitte
2001-03-13We need to build MINFO.Richard Levitte
2000-12-20Stop build when an error occurs.Ulf Möller
2000-11-20'echo on' works better all over than 'echo=on'. We had the sameRichard Levitte
2000-09-25echo=off works on NT, but not on W2K.Richard Levitte
2000-09-23Workaround for tlhelp32.h: place the missing header file in outincUlf Möller
2000-09-23tlhelp32.h is currently missing in Mingw32 (release 2.95.2 and 2.95.2-1)Ulf Möller
2000-03-10Don't generate asm files for no-asm.Ulf Möller
2000-03-10Always use fixed DH parameters created with 'dhparam -C',Bodo Möller
2000-02-28Support assembler for Mingw32.Ulf Möller
2000-01-30Make DSA_generate_parameters, and fix a couple of bugBodo Möller
2000-01-18Rename rsa_oaep_test to the more appropriate name rsa_test for theUlf Möller
1999-07-12Continues NASM support. This might work now. Its still experimental but itDr. Stephen Henson
1999-07-12More NASM support code it still doesn't work but it doesn't work less than itDr. Stephen Henson
1999-06-12BIO pairs.Bodo Möller
1999-06-01Labels longer than eight characters might cause problems.Bodo Möller
1999-05-31More consistency.Bodo Möller
1999-05-22Fixup do_nt.bat for new mk1mf arg order.Dr. Stephen Henson
1999-05-18Change default PKCS#12 iteration count to 2048, include rsa_oeap_test in theDr. Stephen Henson
1999-05-17mk1mf.pl syntax has been changed.Ulf Möller
1999-05-15Various Win32 fixes. Change args in do_ms.bat to put platform last. FixDr. Stephen Henson
1999-05-13mk1mf.pl and mkdef.pl read OPTIONS from toplevel Makefile.Ulf Möller
1999-05-08The libssl32.dll definition file is called ssleay32.def. (why?)Ulf Möller
1999-05-07Generate DLLs with Mingw32.Ulf Möller
1999-05-06Borland C++ builder.Ulf Möller
1999-04-28Autogenerated files.Ulf Möller
1999-04-01Delete some auto generated files and correct a typo in crypto/asn1/p5_pbe.cDr. Stephen Henson
1999-03-12Delete Win32 test with testreq.pem and req: there is already a test withDr. Stephen Henson
1999-03-10Make CC,CFLAG etc get passed to make links and various Win32 fixes.Dr. Stephen Henson
1999-03-09Remove some hard coded paths from Win32 test stuff.Dr. Stephen Henson
1999-03-09Comment out two unimplemented functions from bio.h. Attempt to get theDr. Stephen Henson
1999-03-08Fix Win32 symbol export lists for BIO functions: Added BIO_get_ex_new_index,Ralf S. Engelschall
1999-03-03Fix the Win32 compile environment and add various changes so it will now compileDr. Stephen Henson
1999-02-14Convert ms/do_ms.bat to DOS EOL format of DOS chokes on it.Dr. Stephen Henson
1999-02-14More Win32 fixes and upsdate INSTALL.W32 documentation.Dr. Stephen Henson
1999-02-10First cut for a very conservative source tree cleanup:Ralf S. Engelschall
1999-01-30Fixed ms/32all.bat script: `no_asm' -> `no-asm'Ralf S. Engelschall
1998-12-22*** empty log message ***Ralf S. Engelschall
1998-12-22Various cleanups and fixed by Marc and Ralf to start the OpenTLS projectRalf S. Engelschall
1998-12-21This commit was generated by cvs2svn to track changes on a CVS vendorRalf S. Engelschall
1998-12-21Import of old SSLeay release: SSLeay 0.9.1b (unreleased)SSLeayRalf S. Engelschall
1998-12-21This commit was generated by cvs2svn to track changes on a CVS vendorRalf S. Engelschall
61' href='#n461'>461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
/* $OpenBSD$ */

/*
 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>

#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

#include "tmux.h"

/*
 * Main server functions.
 */

/* Client list. */
struct clients	 clients;
struct clients	 dead_clients;

int		 server_fd;
int		 server_shutdown;
struct event	 server_ev_accept;
struct event	 server_ev_second;

struct paste_stack global_buffers;

int		 server_create_socket(void);
void		 server_loop(void);
int		 server_should_shutdown(void);
void		 server_send_shutdown(void);
void		 server_clean_dead(void);
void		 server_accept_callback(int, short, void *);
void		 server_signal_callback(int, short, void *);
void		 server_child_signal(void);
void		 server_child_exited(pid_t, int);
void		 server_child_stopped(pid_t, int);
void		 server_second_callback(int, short, void *);
void		 server_lock_server(void);
void		 server_lock_sessions(void);

/* Create server socket. */
int
server_create_socket(void)
{
	struct sockaddr_un	sa;
	size_t			size;
	mode_t			mask;
	int			fd;

	memset(&sa, 0, sizeof sa);
	sa.sun_family = AF_UNIX;
	size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path);
	if (size >= sizeof sa.sun_path) {
		errno = ENAMETOOLONG;
		fatal("socket failed");
	}
	unlink(sa.sun_path);

	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
		fatal("socket failed");

	mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
	if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1)
		fatal("bind failed");
	umask(mask);

	if (listen(fd, 16) == -1)
		fatal("listen failed");
	setblocking(fd, 0);

	server_update_socket();

	return (fd);
}

/* Fork new server. */
int
server_start(void)
{
	struct window_pane	*wp;
	int	 		 pair[2];
	char			*cause;
	struct timeval		 tv;
	u_int			 i;

	/* The first client is special and gets a socketpair; create it. */
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
		fatal("socketpair failed");

	switch (fork()) {
	case -1:
		fatal("fork failed");
	case 0:
		break;
	default:
		close(pair[1]);
		return (pair[0]);
	}
	close(pair[0]);

	/*
	 * Must daemonise before loading configuration as the PID changes so
	 * $TMUX would be wrong for sessions created in the config file.
	 */
	if (daemon(1, 0) != 0)
		fatal("daemon failed");

	/* event_init() was called in our parent, need to reinit. */
	if (event_reinit(ev_base) != 0)
		fatal("event_reinit failed");
	clear_signals(0);

	logfile("server");
	log_debug("server started, pid %ld", (long) getpid());

	ARRAY_INIT(&windows);
	RB_INIT(&all_window_panes);
	ARRAY_INIT(&clients);
	ARRAY_INIT(&dead_clients);
	RB_INIT(&sessions);
	RB_INIT(&dead_sessions);
	TAILQ_INIT(&session_groups);
	ARRAY_INIT(&global_buffers);
	mode_key_init_trees();
	key_bindings_init();
	utf8_build();

	start_time = time(NULL);
	log_debug("socket path %s", socket_path);
	setproctitle("server (%s)", socket_path);

	server_fd = server_create_socket();
	server_client_create(pair[1]);

	if (access(SYSTEM_CFG, R_OK) == 0)
		load_cfg(SYSTEM_CFG, NULL, &cfg_causes);
	else if (errno != ENOENT) {
		cfg_add_cause(
		    &cfg_causes, "%s: %s", strerror(errno), SYSTEM_CFG);
	}
	if (cfg_file != NULL)
		load_cfg(cfg_file, NULL, &cfg_causes);

	/*
	 * If there is a session already, put the current window and pane into
	 * more mode.
	 */
	if (!RB_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
		wp = RB_MIN(sessions, &sessions)->curw->window->active;
		window_pane_set_mode(wp, &window_copy_mode);
		window_copy_init_for_output(wp);
		for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
			cause = ARRAY_ITEM(&cfg_causes, i);
			window_copy_add(wp, "%s", cause);
			xfree(cause);
		}
		ARRAY_FREE(&cfg_causes);
	}
	cfg_finished = 1;

	event_set(&server_ev_accept,
	    server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL);
	event_add(&server_ev_accept, NULL);

	memset(&tv, 0, sizeof tv);
	tv.tv_sec = 1;
	evtimer_set(&server_ev_second, server_second_callback, NULL);
	evtimer_add(&server_ev_second, &tv);

	set_signals(server_signal_callback);
	server_loop();
	exit(0);
}

/* Main server loop. */
void
server_loop(void)
{
	while (!server_should_shutdown()) {
		event_loop(EVLOOP_ONCE);

		server_window_loop();
		server_client_loop();

		key_bindings_clean();
		server_clean_dead();
	}
}

/* Check if the server should be shutting down (no more clients or sessions). */
int
server_should_shutdown(void)
{
	u_int	i;

	if (!options_get_number(&global_options, "exit-unattached")) {
		if (!RB_EMPTY(&sessions))
			return (0);
	}
	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
		if (ARRAY_ITEM(&clients, i) != NULL)
			return (0);
	}
	return (1);
}

/* Shutdown the server by killing all clients and windows. */
void
server_send_shutdown(void)
{
	struct client	*c;
	struct session	*s, *next_s;
	u_int		 i;

	for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
		c = ARRAY_ITEM(&clients, i);
		if (c != NULL) {
			if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
				server_client_lost(c);
			else
				server_write_client(c, MSG_SHUTDOWN, NULL, 0);
			c->session = NULL;
		}
	}

	s = RB_MIN(sessions, &sessions);
	while (s != NULL) {
		next_s = RB_NEXT(sessions, &sessions, s);
		session_destroy(s);
		s = next_s;
	}
}

/* Free dead, unreferenced clients and sessions. */
void
server_clean_dead(void)
{
	struct session	*s, *next_s;
	struct client	*c;
	u_int		 i;

	s = RB_MIN(sessions, <