=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/tmux.c,v retrieving revision 1.91 retrieving revision 1.92 diff -c -r1.91 -r1.92 *** src/usr.bin/tmux/tmux.c 2010/10/16 08:42:35 1.91 --- src/usr.bin/tmux/tmux.c 2010/10/18 20:00:03 1.92 *************** *** 1,4 **** ! /* $OpenBSD: tmux.c,v 1.91 2010/10/16 08:42:35 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: tmux.c,v 1.92 2010/10/18 20:00:03 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott *************** *** 18,34 **** #include #include - #include #include #include #include #include #include - #include #include #include - #include #include #include "tmux.h" --- 18,31 ---- *************** *** 37,43 **** 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 */ --- 34,39 ---- *************** *** 45,73 **** struct event_base *ev_base; int debug_level; time_t start_time; ! char *socket_path; int login_shell; - struct env_data { - char *path; - pid_t pid; - u_int 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 *); - __dead void usage(void) { --- 41,60 ---- struct event_base *ev_base; + char *cfg_file; + char *shell_cmd; int debug_level; time_t start_time; ! char socket_path[MAXPATHLEN]; int login_shell; + char *environ_path; + pid_t environ_pid; + u_int environ_idx; __dead void usage(void); ! void parseenvironment(void); ! char *makesocketpath(const char *); __dead void usage(void) { *************** *** 136,149 **** } void ! parse_env(struct env_data *data) { char *env, *path_pid, *pid_idx, buf[256]; size_t len; const char *errstr; long long ll; ! data->pid = -1; if ((env = getenv("TMUX")) == NULL) return; --- 123,136 ---- } void ! parseenvironment(void) { char *env, *path_pid, *pid_idx, buf[256]; size_t len; const char *errstr; long long ll; ! environ_pid = -1; if ((env = getenv("TMUX")) == NULL) return; *************** *** 156,164 **** /* path */ len = path_pid - env; ! data->path = xmalloc (len + 1); ! memcpy(data->path, env, len); ! data->path[len] = '\0'; /* pid */ len = pid_idx - path_pid - 1; --- 143,151 ---- /* path */ len = path_pid - env; ! environ_path = xmalloc(len + 1); ! memcpy(environ_path, env, len); ! environ_path[len] = '\0'; /* pid */ len = pid_idx - path_pid - 1; *************** *** 170,186 **** ll = strtonum(buf, 0, LONG_MAX, &errstr); if (errstr != NULL) return; ! data->pid = ll; /* idx */ ! ll = strtonum(pid_idx+1, 0, UINT_MAX, &errstr); if (errstr != NULL) return; ! data->idx = ll; } char * ! makesockpath(const char *label) { char base[MAXPATHLEN], *path; struct stat sb; --- 157,173 ---- ll = strtonum(buf, 0, LONG_MAX, &errstr); if (errstr != NULL) return; ! environ_pid = ll; /* idx */ ! ll = strtonum(pid_idx + 1, 0, UINT_MAX, &errstr); if (errstr != NULL) return; ! environ_idx = ll; } char * ! makesocketpath(const char *label) { char base[MAXPATHLEN], *path; struct stat sb; *************** *** 240,267 **** 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; #ifdef DEBUG malloc_options = (char *) "AFGJPX"; #endif flags = 0; ! shellcmd = label = path = NULL; ! envdata.path = NULL; login_shell = (**argv == '-'); while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { switch (opt) { --- 227,244 ---- int main(int argc, char **argv) { ! 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; ! label = path = NULL; login_shell = (**argv == '-'); while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { switch (opt) { *************** *** 274,282 **** flags &= ~IDENTIFY_256COLOURS; break; case 'c': ! if (shellcmd != NULL) ! xfree(shellcmd); ! shellcmd = xstrdup(optarg); break; case 'f': if (cfg_file != NULL) --- 251,259 ---- flags &= ~IDENTIFY_256COLOURS; break; case 'c': ! if (shell_cmd != NULL) ! xfree(shell_cmd); ! shell_cmd = xstrdup(optarg); break; case 'f': if (cfg_file != NULL) *************** *** 312,318 **** argc -= optind; argv += optind; ! if (shellcmd != NULL && argc != 0) usage(); log_open_tty(debug_level); --- 289,295 ---- argc -= optind; argv += optind; ! if (shell_cmd != NULL && argc != 0) usage(); log_open_tty(debug_level); *************** *** 448,453 **** --- 425,431 ---- options_set_number(wo, "utf8", 0); } + /* Locate the configuration file. */ if (cfg_file == NULL) { home = getenv("HOME"); if (home == NULL || *home == '\0') { *************** *** 463,483 **** } /* ! * 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); if (path == NULL) { ! /* No -L. Try $TMUX, or default. */ if (label == NULL) { ! path = envdata.path; ! if (path == NULL) label = xstrdup("default"); } /* -L or default set. */ if (label != NULL) { ! if ((path = makesockpath(label)) == NULL) { log_warn("can't create socket"); exit(1); } --- 441,462 ---- } /* ! * Figure out the socket path. If specified on the command-line with -S ! * or -L, use it, otherwise try $TMUX or assume -L default. */ ! parseenvironment(); if (path == NULL) { ! /* If no -L, use the environment. */ if (label == NULL) { ! if (environ_path != NULL) ! path = xstrdup(environ_path); ! else label = xstrdup("default"); } /* -L or default set. */ if (label != NULL) { ! if ((path = makesocketpath(label)) == NULL) { log_warn("can't create socket"); exit(1); } *************** *** 485,665 **** } 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); 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(); ! ! 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); ! } } --- 464,477 ---- } if (label != NULL) xfree(label); ! if (realpath(path, socket_path) == NULL) ! strlcpy(socket_path, path, sizeof socket_path); xfree(path); ! /* Set process title. */ ! setproctitle("%s (%s)", __progname, socket_path); ! /* Pass control to the client. */ ! ev_base = event_init(); ! exit(client_main(argc, argv, flags)); }