/* $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 <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;
int server_create_socket(void);
int server_main(int);
void server_shutdown(void);
void server_child_signal(void);
void server_fill_windows(struct pollfd **);
void server_handle_windows(struct pollfd **);
void server_fill_clients(struct pollfd **);
void server_handle_clients(struct pollfd **);
struct client *server_accept_client(int);
void server_handle_client(struct client *);
void server_handle_window(struct window *, struct window_pane *);
int server_check_window_bell(struct session *, struct window *);
int server_check_window_activity(struct session *,
struct window *);
int server_check_window_content(struct session *, struct window *,
struct window_pane *);
void server_lost_client(struct client *);
void server_check_window(struct window *);
void server_check_redraw(struct client *);
void server_redraw_locked(struct client *);
void server_check_timers(struct client *);
void server_second_timers(void);
int server_update_socket(void);
/* Create a new client. */
struct client *
server_create_client(int fd)
{
struct client *c;
int mode;
u_int i;
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed");
c = xcalloc(1, sizeof *c);
c->fd = fd;
c->in = buffer_create(BUFSIZ);
c->out = buffer_create(BUFSIZ);
ARRAY_INIT(&c->prompt_hdata);
c->tty.fd = -1;
c->title = NULL;
c->session = NULL;
c->tty.sx = 80;
c->tty.sy = 25;
screen_init(&c->status, c->tty.sx, 1, 0);
c->message_string = NULL;
c->prompt_string = NULL;
c->prompt_buffer = NULL;
c->prompt_index = 0;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (ARRAY_ITEM(&clients, i) == NULL) {
ARRAY_SET(&clients, i, c);
return (c);
}
}
ARRAY_ADD(&clients, c);
return (c);
}
/* Find client index. */
int
server_client_index(struct client *c)
{
u_int i;
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
if (c == ARRAY_ITEM(&clients, i))
return (i);
}
return (-1);
}
/* Fork new server. */
int
server_start(char *path)
{
int pair[2], srv_fd, null_fd;
char *cause;
char rpathbuf[MAXPATHLEN];
/* 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, 1) != 0)
fatal("daemon failed");
ARRAY_INIT(&windows);
ARRAY_INIT(&clients);
ARRAY_INIT(&sessions);
key_bindings_init();
utf8_build();
server_locked = 0;
server_password = NULL;
server_activity = time(NULL);
start_time = time(NULL);
socket_path = path;
if (access(SYSTEM_CFG, R_OK) != 0) {
if (errno != ENOENT) {
log_warn("%s", SYSTEM_CFG);
exit(1);
}
} else {
if (load_cfg(SYSTEM_CFG, &cause) != 0) {
log_warnx("%s", cause);
exit(1);
}
}
if (cfg_file != NULL && load_cfg(cfg_file, &cause) != 0) {
log_warnx("%s", cause);
exit(1);
}
logfile("server");
/*
* Close stdin/stdout/stderr. Can't let daemon() do this as they are
* needed until now to print configuration file errors.
*/
if ((null_fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
dup2(null_fd, STDIN_FILENO);
dup2(null_fd, STDOUT_FILENO);
dup2(null_fd, STDERR_FILENO);
if (null_fd > 2)
close(null_fd);
}
log_debug("server started, pid %ld", (long)
|