diff options
Diffstat (limited to 'tmux.c')
-rw-r--r-- | tmux.c | 274 |
1 files changed, 43 insertions, 231 deletions
@@ -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)); } |