summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2010-10-18 20:00:02 +0000
committerNicholas Marriott <nicm@openbsd.org>2010-10-18 20:00:02 +0000
commit248fb14f089216bf384c8914163cc77b4f219154 (patch)
tree7c55d3a23461ce64809f39a3ad01c487e1de53b2
parent31954339d1487d2a179f6180867e67cbd22aabd1 (diff)
Merge the before and after attach client code into one in client.c
(instead of two in tmux.c and client.c).
-rw-r--r--client.c335
-rw-r--r--server.c10
-rw-r--r--tmux.c274
-rw-r--r--tmux.h13
4 files changed, 296 insertions, 336 deletions
diff --git a/client.c b/client.c
index d9682b49..35a2e4e8 100644
--- a/client.c
+++ b/client.c
@@ -28,7 +28,6 @@
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
-#include <syslog.h>
#include <unistd.h>
#include "tmux.h"
@@ -37,77 +36,171 @@ struct imsgbuf client_ibuf;
struct event client_event;
const char *client_exitmsg;
int client_exitval;
+int client_attached;
+int client_connect(char *, int);
void client_send_identify(int);
void client_send_environ(void);
void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void);
void client_signal(int, short, void *);
void client_callback(int, short, void *);
-int client_dispatch(void);
+int client_dispatch_attached(void);
+int client_dispatch_wait(void *);
-struct imsgbuf *
-client_init(char *path, int cmdflags, int flags)
+/* Connect client to server. */
+int
+client_connect(char *path, int start_server)
{
struct sockaddr_un sa;
size_t size;
int fd, mode;
- char rpathbuf[MAXPATHLEN];
-
- if (realpath(path, rpathbuf) == NULL)
- strlcpy(rpathbuf, path, sizeof rpathbuf);
- setproctitle("client (%s)", rpathbuf);
memset(&sa, 0, sizeof sa);
sa.sun_family = AF_UNIX;
size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
if (size >= sizeof sa.sun_path) {
errno = ENAMETOOLONG;
- goto not_found;
+ return (-1);
}
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
fatal("socket failed");
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
- if (!(cmdflags & CMD_STARTSERVER))
- goto not_found;
+ if (!start_server)
+ goto failed;
switch (errno) {
case ECONNREFUSED:
if (unlink(path) != 0)
- goto not_found;
+ goto failed;
/* FALLTHROUGH */
case ENOENT:
- if ((fd = server_start(path)) == -1)
- goto start_failed;
- goto server_started;
+ if ((fd = server_start()) == -1)
+ goto failed;
+ break;
+ default:
+ goto failed;
}
- goto not_found;
}
-server_started:
if ((mode = fcntl(fd, F_GETFL)) == -1)
fatal("fcntl failed");
if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl failed");
+ return (fd);
+
+failed:
+ close(fd);
+ return (-1);
+}
+
+/* Client main loop. */
+int
+client_main(int argc, char **argv, int flags)
+{
+ struct cmd *cmd;
+ struct cmd_list *cmdlist;
+ struct msg_command_data cmddata;
+ int cmdflags, fd;
+ enum msgtype msg;
+ char *cause;
+
+ /* Set up the initial command. */
+ cmdflags = 0;
+ if (shell_cmd != NULL) {
+ msg = MSG_SHELL;
+ cmdflags = CMD_STARTSERVER;
+ } else if (argc == 0) {
+ msg = MSG_COMMAND;
+ cmdflags = CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
+ } else {
+ msg = MSG_COMMAND;
+
+ /*
+ * It sucks parsing the command string twice (in client and
+ * later in server) but it is necessary to get the start server
+ * flag.
+ */
+ if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
+ log_warnx("%s", cause);
+ return (1);
+ }
+ cmdflags &= ~CMD_STARTSERVER;
+ TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
+ if (cmd->entry->flags & CMD_STARTSERVER)
+ cmdflags |= CMD_STARTSERVER;
+ if (cmd->entry->flags & CMD_SENDENVIRON)
+ cmdflags |= CMD_SENDENVIRON;
+ if (cmd->entry->flags & CMD_CANTNEST)
+ cmdflags |= CMD_CANTNEST;
+ }
+ cmd_list_free(cmdlist);
+ }
+
+ /*
+ * Check if this could be a nested session, if the command can't nest:
+ * if the socket path matches $TMUX, this is probably the same server.
+ */
+ if (shell_cmd == NULL && environ_path != NULL &&
+ cmdflags & CMD_CANTNEST && strcmp(socket_path, environ_path) == 0) {
+ log_warnx("sessions should be nested with care. "
+ "unset $TMUX to force.");
+ return (1);
+ }
+
+ /* Initialise the client socket and start the server. */
+ fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
+ if (fd == -1) {
+ log_warn("failed to connect to server");
+ return (1);
+ }
+
+ /* Set process title, log and signals now this is the client. */
+ setproctitle("client (%s)", socket_path);
+ logfile("client");
+
+ /* Create imsg. */
imsg_init(&client_ibuf, fd);
- event_set(&client_event, fd, EV_READ, client_callback, NULL);
+ event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
+ /* Establish signal handlers. */
+ set_signals(client_signal);
+
+ /* Send initial environment. */
if (cmdflags & CMD_SENDENVIRON)
client_send_environ();
client_send_identify(flags);
- return (&client_ibuf);
+ /* Send first command. */
+ if (msg == MSG_COMMAND) {
+ /* Fill in command line arguments. */
+ cmddata.pid = environ_pid;
+ cmddata.idx = environ_idx;
+
+ /* Prepare command for server. */
+ cmddata.argc = argc;
+ if (cmd_pack_argv(
+ argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
+ log_warnx("command too long");
+ return (1);
+ }
+
+ client_write_server(msg, &cmddata, sizeof cmddata);
+ } else if (msg == MSG_SHELL)
+ client_write_server(msg, NULL, 0);
-start_failed:
- log_warnx("server failed to start");
- return (NULL);
+ /* Set the event and dispatch. */
+ client_update_event();
+ event_dispatch();
-not_found:
- log_warn("server not found");
- return (NULL);
+ /* Print the exit message, if any, and exit. */
+ if (client_attached && client_exitmsg != NULL && !login_shell)
+ printf("[%s]\n", client_exitmsg);
+ return (client_exitval);
}
+/* Send identify message to server with the file descriptors. */
void
client_send_identify(int flags)
{
@@ -132,13 +225,16 @@ client_send_identify(int flags)
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
- imsg_compose(&client_ibuf, MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
+ imsg_compose(&client_ibuf,
+ MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
if ((fd = dup(STDERR_FILENO)) == -1)
fatal("dup failed");
- imsg_compose(&client_ibuf, MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
+ imsg_compose(&client_ibuf,
+ MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
}
+/* Forward entire environment to server. */
void
client_send_environ(void)
{
@@ -152,12 +248,14 @@ client_send_environ(void)
}
}
+/* Write a message to the server without a file descriptor. */
void
client_write_server(enum msgtype type, void *buf, size_t len)
{
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
}
+/* Update client event based on whether it needs to read or read and write. */
void
client_update_event(void)
{
@@ -167,91 +265,74 @@ client_update_event(void)
events = EV_READ;
if (client_ibuf.w.queued > 0)
events |= EV_WRITE;
- event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
+ event_set(
+ &client_event, client_ibuf.fd, events, client_callback, shell_cmd);
event_add(&client_event, NULL);
}
-__dead void
-client_main(void)
-{
- logfile("client");
-
- /* Note: event_init() has already been called. */
-
- /* Set up signals. */
- set_signals(client_signal);
-
- /*
- * Send a resize message immediately in case the terminal size has
- * changed between the identify message to the server and the MSG_READY
- * telling us to move into the client code.
- */
- client_write_server(MSG_RESIZE, NULL, 0);
-
- /*
- * imsg_read in the first client poll loop (before the terminal has
- * been initialised) may have read messages into the buffer after the
- * MSG_READY switched to here. Process anything outstanding now to
- * avoid hanging waiting for messages that have already arrived.
- */
- if (client_dispatch() != 0)
- goto out;
-
- /* Set the event and dispatch. */
- client_update_event();
- event_dispatch();
-
-out:
- /* Print the exit message, if any, and exit. */
- if (client_exitmsg != NULL && !login_shell)
- printf("[%s]\n", client_exitmsg);
- exit(client_exitval);
-}
-
+/* Callback to handle signals in the client. */
/* ARGSUSED */
void
client_signal(int sig, unused short events, unused void *data)
{
- struct sigaction sigact;
+ struct sigaction sigact;
+ int status;
- switch (sig) {
- case SIGHUP:
- client_exitmsg = "lost tty";
- client_exitval = 1;
- client_write_server(MSG_EXITING, NULL, 0);
- break;
- case SIGTERM:
- client_exitmsg = "terminated";
- client_exitval = 1;
- client_write_server(MSG_EXITING, NULL, 0);
- break;
- case SIGWINCH:
- client_write_server(MSG_RESIZE, NULL, 0);
- break;
- case SIGCONT:
- memset(&sigact, 0, sizeof sigact);
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = SA_RESTART;
- sigact.sa_handler = SIG_IGN;
- if (sigaction(SIGTSTP, &sigact, NULL) != 0)
- fatal("sigaction failed");
- client_write_server(MSG_WAKEUP, NULL, 0);
- break;
+ if (!client_attached) {
+ switch (sig) {
+ case SIGCHLD:
+ waitpid(WAIT_ANY, &status, WNOHANG);
+ break;
+ case SIGTERM:
+ event_loopexit(NULL);
+ break;
+ }
+ } else {
+ switch (sig) {
+ case SIGHUP:
+ client_exitmsg = "lost tty";
+ client_exitval = 1;
+ client_write_server(MSG_EXITING, NULL, 0);
+ break;
+ case SIGTERM:
+ client_exitmsg = "terminated";
+ client_exitval = 1;
+ client_write_server(MSG_EXITING, NULL, 0);
+ break;
+ case SIGWINCH:
+ client_write_server(MSG_RESIZE, NULL, 0);
+ break;
+ case SIGCONT:
+ memset(&sigact, 0, sizeof sigact);
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = SA_RESTART;
+ sigact.sa_handler = SIG_IGN;
+ if (sigaction(SIGTSTP, &sigact, NULL) != 0)
+ fatal("sigaction failed");
+ client_write_server(MSG_WAKEUP, NULL, 0);
+ break;
+ }
}
client_update_event();
}
+/* Callback for client imsg read events. */
/* ARGSUSED */
void
-client_callback(unused int fd, short events, unused void *data)
+client_callback(unused int fd, short events, void *data)
{
ssize_t n;
+ int retval;
if (events & EV_READ) {
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
goto lost_server;
- if (client_dispatch() != 0) {
+ if (client_attached)
+ retval = client_dispatch_attached();
+ else
+ retval = client_dispatch_wait(data);
+ if (retval != 0) {
event_loopexit(NULL);
return;
}
@@ -271,8 +352,76 @@ lost_server:
event_loopexit(NULL);
}
+/* Dispatch imsgs when in wait state (before MSG_READY). */
+int
+client_dispatch_wait(void *data)
+{
+ struct imsg imsg;
+ ssize_t n, datalen;
+ struct msg_shell_data shelldata;
+ struct msg_exit_data exitdata;
+ const char *shellcmd = data;
+
+ if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
+ fatalx("imsg_read failed");
+
+ for (;;) {
+ if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
+ fatalx("imsg_get failed");
+ if (n == 0)
+ return (0);
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+
+ switch (imsg.hdr.type) {
+ case MSG_EXIT:
+ case MSG_SHUTDOWN:
+ if (datalen != sizeof exitdata) {
+ if (datalen != 0)
+ fatalx("bad MSG_EXIT size");
+ } else {
+ memcpy(&exitdata, imsg.data, sizeof exitdata);
+ client_exitval = exitdata.retcode;
+ }
+ imsg_free(&imsg);
+ return (-1);
+ case MSG_READY:
+ if (datalen != 0)
+ fatalx("bad MSG_READY size");
+
+ client_attached = 1;
+ break;
+ case MSG_VERSION:
+ if (datalen != 0)
+ fatalx("bad MSG_VERSION size");
+
+ log_warnx("protocol version mismatch (client %u, "
+ "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
+ client_exitval = 1;
+
+ imsg_free(&imsg);
+ return (-1);
+ case MSG_SHELL:
+ if (datalen != sizeof shelldata)
+ fatalx("bad MSG_SHELL size");
+ memcpy(&shelldata, imsg.data, sizeof shelldata);
+ shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
+
+ clear_signals(0);
+
+ shell_exec(shelldata.shell, shellcmd);
+ /* NOTREACHED */
+ default:
+ fatalx("unexpected message");
+ }
+
+ imsg_free(&imsg);
+ }
+}
+
+/* Dispatch imsgs in attached state (after MSG_READY). */
+/* ARGSUSED */
int
-client_dispatch(void)
+client_dispatch_attached(void)
{
struct imsg imsg;
struct msg_lock_data lockdata;
diff --git a/server.c b/server.c
index 721bb570..7a4e5fcf 100644
--- a/server.c
+++ b/server.c
@@ -106,11 +106,11 @@ server_create_socket(void)
/* Fork new server. */
int
-server_start(char *path)
+server_start(void)
{
struct window_pane *wp;
int pair[2];
- char rpathbuf[MAXPATHLEN], *cause;
+ char *cause;
struct timeval tv;
u_int i;
@@ -155,12 +155,8 @@ server_start(char *path)
utf8_build();
start_time = time(NULL);
- socket_path = path;
-
- if (realpath(socket_path, rpathbuf) == NULL)
- strlcpy(rpathbuf, socket_path, sizeof rpathbuf);
log_debug("socket path %s", socket_path);
- setproctitle("server (%s)", rpathbuf);
+ setproctitle("server (%s)", socket_path);
server_fd = server_create_socket();
server_client_create(pair[1]);
diff --git a/tmux.c b/tmux.c
index f6601cdf..3a3f82f9 100644
--- a/tmux.c
+++ b/tmux.c
@@ -18,17 +18,14 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/wait.h>
#include <errno.h>
#include <event.h>
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
-#include <signal.h>
#include <stdlib.h>
#include <string.h>
-#include <syslog.h>
#include <unistd.h>
#include "tmux.h"
@@ -37,7 +34,6 @@
extern char *malloc_options;
#endif
-char *cfg_file;
struct options global_options; /* server options */
struct options global_s_options; /* session options */
struct options global_w_options; /* window options */
@@ -45,28 +41,19 @@ struct environ global_environ;
struct event_base *ev_base;
+char *cfg_file;
+char *shell_cmd;
int debug_level;
time_t start_time;
-char *socket_path;
+char socket_path[MAXPATHLEN];
int login_shell;
-
-struct env_data {
- char *path;
- pid_t pid;
- u_int idx;
-};
+char *environ_path;
+pid_t environ_pid;
+u_int environ_idx;
__dead void usage(void);
-void parse_env(struct env_data *);
-char *makesockpath(const char *);
-__dead void shell_exec(const char *, const char *);
-
-struct imsgbuf *main_ibuf;
-struct event main_event;
-
-void main_signal(int, short, unused void *);
-void main_callback(int, short, void *);
-void main_dispatch(const char *);
+void parseenvironment(void);
+char *makesocketpath(const char *);
__dead void
usage(void)
@@ -136,14 +123,14 @@ areshell(const char *shell)
}
void
-parse_env(struct env_data *data)
+parseenvironment(void)
{
char *env, *path_pid, *pid_idx, buf[256];
size_t len;
const char *errstr;
long long ll;
- data->pid = -1;
+ environ_pid = -1;
if ((env = getenv("TMUX")) == NULL)
return;
@@ -156,9 +143,9 @@ parse_env(struct env_data *data)
/* path */
len = path_pid - env;
- data->path = xmalloc (len + 1);
- memcpy(data->path, env, len);
- data->path[len] = '\0';
+ environ_path = xmalloc(len + 1);
+ memcpy(environ_path, env, len);
+ environ_path[len] = '\0';
/* pid */
len = pid_idx - path_pid - 1;
@@ -170,17 +157,17 @@ parse_env(struct env_data *data)
ll = strtonum(buf, 0, LONG_MAX, &errstr);
if (errstr != NULL)
return;
- data->pid = ll;
+ environ_pid = ll;
/* idx */
- ll = strtonum(pid_idx+1, 0, UINT_MAX, &errstr);
+ ll = strtonum(pid_idx + 1, 0, UINT_MAX, &errstr);
if (errstr != NULL)
return;
- data->idx = ll;
+ environ_idx = ll;
}
char *
-makesockpath(const char *label)
+makesocketpath(const char *label)
{
char base[MAXPATHLEN], *path;
struct stat sb;
@@ -240,28 +227,18 @@ shell_exec(const char *shell, const char *shellcmd)
int
main(int argc, char **argv)
{
- struct cmd_list *cmdlist;
- struct cmd *cmd;
- enum msgtype msg;
- struct passwd *pw;
- struct options *oo, *so, *wo;
- struct keylist *keylist;
- struct env_data envdata;
- struct msg_command_data cmddata;
- char *s, *shellcmd, *path, *label, *home, *cause;
- char **var;
- void *buf;
- size_t len;
- int opt, flags, quiet = 0, cmdflags = 0;
- short events;
+ struct passwd *pw;
+ struct options *oo, *so, *wo;
+ struct keylist *keylist;
+ char *s, *path, *label, *home, **var;
+ int opt, flags, quiet = 0;
#ifdef DEBUG
malloc_options = (char *) "AFGJPX";
#endif
flags = 0;
- shellcmd = label = path = NULL;
- envdata.path = NULL;
+ label = path = NULL;
login_shell = (**argv == '-');
while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) {
switch (opt) {
@@ -274,9 +251,9 @@ main(int argc, char **argv)
flags &= ~IDENTIFY_256COLOURS;
break;
case 'c':
- if (shellcmd != NULL)
- xfree(shellcmd);
- shellcmd = xstrdup(optarg);
+ if (shell_cmd != NULL)
+ xfree(shell_cmd);
+ shell_cmd = xstrdup(optarg);
break;
case 'f':
if (cfg_file != NULL)
@@ -312,7 +289,7 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
- if (shellcmd != NULL && argc != 0)
+ if (shell_cmd != NULL && argc != 0)
usage();
log_open_tty(debug_level);
@@ -448,6 +425,7 @@ main(int argc, char **argv)
options_set_number(wo, "utf8", 0);
}
+ /* Locate the configuration file. */
if (cfg_file == NULL) {
home = getenv("HOME");
if (home == NULL || *home == '\0') {
@@ -463,21 +441,22 @@ main(int argc, char **argv)
}
/*
- * Figure out the socket path. If specified on the command-line with
- * -S or -L, use it, otherwise try $TMUX or assume -L default.
+ * Figure out the socket path. If specified on the command-line with -S
+ * or -L, use it, otherwise try $TMUX or assume -L default.
*/
- parse_env(&envdata);
+ parseenvironment();
if (path == NULL) {
- /* No -L. Try $TMUX, or default. */
+ /* If no -L, use the environment. */
if (label == NULL) {
- path = envdata.path;
- if (path == NULL)
+ if (environ_path != NULL)
+ path = xstrdup(environ_path);
+ else
label = xstrdup("default");
}
/* -L or default set. */
if (label != NULL) {
- if ((path = makesockpath(label)) == NULL) {
+ if ((path = makesocketpath(label)) == NULL) {
log_warn("can't create socket");
exit(1);
}
@@ -485,181 +464,14 @@ main(int argc, char **argv)
}
if (label != NULL)
xfree(label);
-
- if (shellcmd != NULL) {
- msg = MSG_SHELL;
- buf = NULL;
- len = 0;
- } else {
- cmddata.pid = envdata.pid;
- cmddata.idx = envdata.idx;
-
- /* Prepare command for server. */
- cmddata.argc = argc;
- if (cmd_pack_argv(
- argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
- log_warnx("command too long");
- exit(1);
- }
-
- msg = MSG_COMMAND;
- buf = &cmddata;
- len = sizeof cmddata;
- }
-
- if (shellcmd != NULL)
- cmdflags |= CMD_STARTSERVER;
- else if (argc == 0) /* new-session is the default */
- cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON|CMD_CANTNEST;
- else {
- /*
- * It sucks parsing the command string twice (in client and
- * later in server) but it is necessary to get the start server
- * flag.
- */
- if ((cmdlist = cmd_list_parse(argc, argv, &cause)) == NULL) {
- log_warnx("%s", cause);
- exit(1);
- }
- cmdflags &= ~CMD_STARTSERVER;
- TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
- if (cmd->entry->flags & CMD_STARTSERVER)
- cmdflags |= CMD_STARTSERVER;
- if (cmd->entry->flags & CMD_SENDENVIRON)
- cmdflags |= CMD_SENDENVIRON;
- if (cmd->entry->flags & CMD_CANTNEST)
- cmdflags |= CMD_CANTNEST;
- }
- cmd_list_free(cmdlist);
- }
-
- /*
- * Check if this could be a nested session, if the command can't nest:
- * if the socket path matches $TMUX, this is probably the same server.
- */
- if (shellcmd == NULL && envdata.path != NULL &&
- cmdflags & CMD_CANTNEST &&
- (path == envdata.path || strcmp(path, envdata.path) == 0)) {
- log_warnx("sessions should be nested with care. "
- "unset $TMUX to force.");
- exit(1);
- }
-
- ev_base = event_init();
- set_signals(main_signal);
-
- /* Initialise the client socket/start the server. */
- if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
- exit(1);
+ if (realpath(path, socket_path) == NULL)
+ strlcpy(socket_path, path, sizeof socket_path);
xfree(path);
- imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
-
- events = EV_READ;
- if (main_ibuf->w.queued > 0)
- events |= EV_WRITE;
- event_set(&main_event, main_ibuf->fd, events, main_callback, shellcmd);
- event_add(&main_event, NULL);
-
- event_dispatch();
+ /* Set process title. */
+ setproctitle("%s (%s)", __progname, socket_path);
- event_del(&main_event);
-
- clear_signals(0);
- client_main(); /* doesn't return */
-}
-
-/* ARGSUSED */
-void
-main_signal(int sig, unused short events, unused void *data)
-{
- int status;
-
- switch (sig) {
- case SIGTERM:
- exit(1);
- case SIGCHLD:
- waitpid(WAIT_ANY, &status, WNOHANG);
- break;
- }
-}
-
-/* ARGSUSED */
-void
-main_callback(unused int fd, short events, void *data)
-{
- char *shellcmd = data;
-
- if (events & EV_READ)
- main_dispatch(shellcmd);
-
- if (events & EV_WRITE) {
- if (msgbuf_write(&main_ibuf->w) < 0)
- fatalx("msgbuf_write failed");
- }
-
- event_del(&main_event);
- events = EV_READ;
- if (main_ibuf->w.queued > 0)
- events |= EV_WRITE;
- event_set(&main_event, main_ibuf->fd, events, main_callback, shellcmd);
- event_add(&main_event, NULL);
-}
-
-void
-main_dispatch(const char *shellcmd)
-{
- struct imsg imsg;
- ssize_t n, datalen;
- struct msg_shell_data shelldata;
- struct msg_exit_data exitdata;
-
- if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
- fatalx("imsg_read failed");
-
- for (;;) {
- if ((n = imsg_get(main_ibuf, &imsg)) == -1)
- fatalx("imsg_get failed");
- if (n == 0)
- return;
- datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
-
- switch (imsg.hdr.type) {
- case MSG_EXIT:
- case MSG_SHUTDOWN:
- if (datalen != sizeof exitdata) {
- if (datalen != 0)
- fatalx("bad MSG_EXIT size");
- exit(0);
- }
- memcpy(&exitdata, imsg.data, sizeof exitdata);
- exit(exitdata.retcode);
- case MSG_READY:
- if (datalen != 0)
- fatalx("bad MSG_READY size");
-
- event_loopexit(NULL); /* move to client_main() */
- break;
- case MSG_VERSION:
- if (datalen != 0)
- fatalx("bad MSG_VERSION size");
-
- log_warnx("protocol version mismatch (client %u, "
- "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
- exit(1);
- case MSG_SHELL:
- if (datalen != sizeof shelldata)
- fatalx("bad MSG_SHELL size");
- memcpy(&shelldata, imsg.data, sizeof shelldata);
- shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
-
- clear_signals(0);
-
- shell_exec(shelldata.shell, shellcmd);
- default:
- fatalx("unexpected message");
- }
-
- imsg_free(&imsg);
- }
+ /* Pass control to the client. */
+ ev_base = event_init();
+ exit(client_main(argc, argv, flags));
}
diff --git a/tmux.h b/tmux.h
index 2e1c8e1d..47837851 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1291,15 +1291,19 @@ extern struct options global_w_options;
extern struct environ global_environ;
extern struct event_base *ev_base;
extern char *cfg_file;
+extern char *shell_cmd;
extern int debug_level;
-extern int be_quiet;
extern time_t start_time;
-extern char *socket_path;
+extern char socket_path[MAXPATHLEN];
extern int login_shell;
+extern char *environ_path;
+extern pid_t environ_pid;
+extern u_int environ_idx;
void logfile(const char *);
const char *getshell(void);
int checkshell(const char *);
int areshell(const char *);
+__dead void shell_exec(const char *, const char *);
/* cfg.c */
extern int cfg_finished;
@@ -1598,8 +1602,7 @@ void cmd_buffer_free(struct cmd *);
size_t cmd_buffer_print(struct cmd *, char *, size_t);
/* client.c */
-struct imsgbuf *client_init(char *, int, int);
-__dead void client_main(void);
+int client_main(int, char **, int);
/* key-bindings.c */
extern struct key_bindings key_bindings;
@@ -1622,7 +1625,7 @@ const char *key_string_lookup_key(int);
/* server.c */
extern struct clients clients;
extern struct clients dead_clients;
-int server_start(char *);
+int server_start(void);
void server_update_socket(void);
/* server-client.c */