diff --git a/Makefile b/Makefile index 32195762..cf856b6c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # $OpenBSD$ PROG= tmux -SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \ +SRCS= attributes.c buffer-poll.c buffer.c cfg.c \ client.c clock.c cmd-attach-session.c cmd-bind-key.c \ cmd-break-pane.c cmd-choose-session.c cmd-choose-window.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ diff --git a/client-fn.c b/client-fn.c deleted file mode 100644 index 789ac427..00000000 --- a/client-fn.c +++ /dev/null @@ -1,90 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2007 Nicholas Marriott - * - * 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 - -#include -#include -#include - -#include "tmux.h" - -void -client_fill_session(struct msg_command_data *data) -{ - char *env, *ptr1, *ptr2, buf[256]; - size_t len; - const char *errstr; - long long ll; - - data->pid = -1; - if ((env = getenv("TMUX")) == NULL) - return; - - if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) - return; - for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) - ; - if (*ptr1 != ',') - return; - ptr1++; - ptr2++; - - len = ptr2 - ptr1 - 1; - if (len > (sizeof buf) - 1) - return; - memcpy(buf, ptr1, len); - buf[len] = '\0'; - - ll = strtonum(buf, 0, LONG_MAX, &errstr); - if (errstr != NULL) - return; - data->pid = ll; - - ll = strtonum(ptr2, 0, UINT_MAX, &errstr); - if (errstr != NULL) - return; - data->idx = ll; -} - -void -client_write_server( - struct client_ctx *cctx, enum msgtype type, void *buf, size_t len) -{ - imsg_compose(&cctx->ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); -} - -void -client_suspend(void) -{ - struct sigaction act; - - memset(&act, 0, sizeof act); - sigemptyset(&act.sa_mask); - act.sa_flags = SA_RESTART; - - act.sa_handler = SIG_DFL; - if (sigaction(SIGTSTP, &act, NULL) != 0) - fatal("sigaction failed"); - - act.sa_handler = sighandler; - if (sigaction(SIGCONT, &act, NULL) != 0) - fatal("sigaction failed"); - - kill(getpid(), SIGTSTP); -} diff --git a/client.c b/client.c index e7118a3b..b048645e 100644 --- a/client.c +++ b/client.c @@ -33,10 +33,16 @@ #include "tmux.h" -void client_send_environ(struct client_ctx *); +struct imsgbuf client_ibuf; +const char *client_exitmsg; -int -client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) +void client_send_environ(void); +void client_write_server(enum msgtype, void *, size_t); +int client_dispatch(void); +void client_suspend(void); + +struct imsgbuf * +client_init(char *path, int cmdflags, int flags) { struct sockaddr_un sa; struct stat sb; @@ -93,10 +99,10 @@ server_started: fatal("fcntl failed"); if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); - imsg_init(&cctx->ibuf, fd); + imsg_init(&client_ibuf, fd); if (cmdflags & CMD_SENDENVIRON) - client_send_environ(cctx); + client_send_environ(); if (isatty(STDIN_FILENO)) { if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) fatal("ioctl(TIOCGWINSZ)"); @@ -114,23 +120,23 @@ server_started: if ((fd2 = dup(STDIN_FILENO)) == -1) fatal("dup failed"); - imsg_compose(&cctx->ibuf, MSG_IDENTIFY, + imsg_compose(&client_ibuf, MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd2, &data, sizeof data); } - return (0); + return (&client_ibuf); start_failed: log_warnx("server failed to start"); - return (1); + return (NULL); not_found: log_warn("server not found"); - return (1); + return (NULL); } void -client_send_environ(struct client_ctx *cctx) +client_send_environ(void) { char **var; struct msg_environ_data data; @@ -138,12 +144,18 @@ client_send_environ(struct client_ctx *cctx) for (var = environ; *var != NULL; var++) { if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) continue; - client_write_server(cctx, MSG_ENVIRON, &data, sizeof data); + client_write_server(MSG_ENVIRON, &data, sizeof data); } } -int -client_main(struct client_ctx *cctx) +void +client_write_server(enum msgtype type, void *buf, size_t len) +{ + imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len); +} + +__dead void +client_main(void) { struct pollfd pfd; int n, nfds; @@ -158,29 +170,31 @@ client_main(struct client_ctx *cctx) * MSG_READY switched to here. Process anything outstanding now so poll * doesn't hang waiting for messages that have already arrived. */ - if (client_msg_dispatch(cctx) != 0) + if (client_dispatch() != 0) goto out; for (;;) { - if (sigterm) - client_write_server(cctx, MSG_EXITING, NULL, 0); + if (sigterm) { + client_exitmsg = "terminated"; + client_write_server(MSG_EXITING, NULL, 0); + } if (sigchld) { waitpid(WAIT_ANY, NULL, WNOHANG); sigchld = 0; } if (sigwinch) { - client_write_server(cctx, MSG_RESIZE, NULL, 0); + client_write_server(MSG_RESIZE, NULL, 0); sigwinch = 0; } if (sigcont) { siginit(); - client_write_server(cctx, MSG_WAKEUP, NULL, 0); + client_write_server(MSG_WAKEUP, NULL, 0); sigcont = 0; } - pfd.fd = cctx->ibuf.fd; + pfd.fd = client_ibuf.fd; pfd.events = POLLIN; - if (cctx->ibuf.w.queued > 0) + if (client_ibuf.w.queued > 0) pfd.events |= POLLOUT; if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { @@ -195,67 +209,41 @@ client_main(struct client_ctx *cctx) fatalx("socket error"); if (pfd.revents & POLLIN) { - if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { - cctx->exittype = CCTX_DIED; + if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) { + client_exitmsg = "lost server"; break; } - if (client_msg_dispatch(cctx) != 0) + if (client_dispatch() != 0) break; } if (pfd.revents & POLLOUT) { - if (msgbuf_write(&cctx->ibuf.w) < 0) { - cctx->exittype = CCTX_DIED; + if (msgbuf_write(&client_ibuf.w) < 0) { + client_exitmsg = "lost server"; break; } } } out: - /* - * Print exit status message, unless running as a login shell where it - * would either be pointless or irritating. - */ - if (sigterm) { - printf("[terminated]\n"); - return (1); - } - switch (cctx->exittype) { - case CCTX_DIED: - printf("[lost server]\n"); - return (0); - case CCTX_SHUTDOWN: - if (!login_shell) - printf("[server exited]\n"); - return (0); - case CCTX_EXIT: - if (cctx->errstr != NULL) { - printf("[error: %s]\n", cctx->errstr); - return (1); - } - if (!login_shell) - printf("[exited]\n"); - return (0); - case CCTX_DETACH: + /* Print the exit message, if any, and exit. */ + if (client_exitmsg != NULL) { if (!login_shell) - printf("[detached]\n"); - return (0); - default: - printf("[unknown error]\n"); - return (1); + printf("[%s]\n", client_exitmsg); + exit(1); } + exit(0); } int -client_msg_dispatch(struct client_ctx *cctx) +client_dispatch(void) { struct imsg imsg; - struct msg_print_data printdata; struct msg_lock_data lockdata; ssize_t n, datalen; for (;;) { - if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + if ((n = imsg_get(&client_ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); @@ -266,25 +254,15 @@ client_msg_dispatch(struct client_ctx *cctx) if (datalen != 0) fatalx("bad MSG_DETACH size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_DETACH; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "detached"; break; - case MSG_ERROR: - if (datalen != sizeof printdata) - fatalx("bad MSG_ERROR size"); - memcpy(&printdata, imsg.data, sizeof printdata); - - printdata.msg[(sizeof printdata.msg) - 1] = '\0'; - /* Error string used after exit message from server. */ - cctx->errstr = xstrdup(printdata.msg); - imsg_free(&imsg); - return (-1); case MSG_EXIT: if (datalen != 0) fatalx("bad MSG_EXIT size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_EXIT; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "exited"; break; case MSG_EXITED: if (datalen != 0) @@ -296,8 +274,8 @@ client_msg_dispatch(struct client_ctx *cctx) if (datalen != 0) fatalx("bad MSG_SHUTDOWN size"); - client_write_server(cctx, MSG_EXITING, NULL, 0); - cctx->exittype = CCTX_SHUTDOWN; + client_write_server(MSG_EXITING, NULL, 0); + client_exitmsg = "server exited"; break; case MSG_SUSPEND: if (datalen != 0) @@ -312,7 +290,7 @@ client_msg_dispatch(struct client_ctx *cctx) lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; system(lockdata.cmd); - client_write_server(cctx, MSG_UNLOCK, NULL, 0); + client_write_server(MSG_UNLOCK, NULL, 0); break; default: fatalx("unexpected message"); @@ -321,3 +299,23 @@ client_msg_dispatch(struct client_ctx *cctx) imsg_free(&imsg); } } + +void +client_suspend(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof act); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + + act.sa_handler = SIG_DFL; + if (sigaction(SIGTSTP, &act, NULL) != 0) + fatal("sigaction failed"); + + act.sa_handler = sighandler; + if (sigaction(SIGCONT, &act, NULL) != 0) + fatal("sigaction failed"); + + kill(getpid(), SIGTSTP); +} diff --git a/tmux.c b/tmux.c index 6e747bbe..f6d96c54 100644 --- a/tmux.c +++ b/tmux.c @@ -53,9 +53,10 @@ char *socket_path; int login_shell; __dead void usage(void); +void fill_session(struct msg_command_data *); char *makesockpath(const char *); int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); -int dispatch_imsg(struct client_ctx *, const char *, int *); +int dispatch_imsg(struct imsgbuf *, const char *, int *); __dead void shell_exec(const char *, const char *); __dead void @@ -215,6 +216,44 @@ areshell(const char *shell) return (0); } +void +fill_session(struct msg_command_data *data) +{ + char *env, *ptr1, *ptr2, buf[256]; + size_t len; + const char *errstr; + long long ll; + + data->pid = -1; + if ((env = getenv("TMUX")) == NULL) + return; + + if ((ptr2 = strrchr(env, ',')) == NULL || ptr2 == env) + return; + for (ptr1 = ptr2 - 1; ptr1 > env && *ptr1 != ','; ptr1--) + ; + if (*ptr1 != ',') + return; + ptr1++; + ptr2++; + + len = ptr2 - ptr1 - 1; + if (len > (sizeof buf) - 1) + return; + memcpy(buf, ptr1, len); + buf[len] = '\0'; + + ll = strtonum(buf, 0, LONG_MAX, &errstr); + if (errstr != NULL) + return; + data->pid = ll; + + ll = strtonum(ptr2, 0, UINT_MAX, &errstr); + if (errstr != NULL) + return; + data->idx = ll; +} + char * makesockpath(const char *label) { @@ -248,7 +287,7 @@ prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) { static struct msg_command_data cmddata; - client_fill_session(&cmddata); + fill_session(&cmddata); cmddata.argc = argc; if (cmd_pack_argv(argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { @@ -266,20 +305,19 @@ prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv) int main(int argc, char **argv) { - struct client_ctx cctx; - struct cmd_list *cmdlist; - struct cmd *cmd; - struct pollfd pfd; - enum msgtype msg; - struct passwd *pw; - struct options *so, *wo; - struct keylist *keylist; - char *s, *shellcmd, *path, *label, *home, *cause; - char cwd[MAXPATHLEN], **var; - void *buf; - size_t len; - int retcode, opt, flags, cmdflags = 0; - int nfds; + struct cmd_list *cmdlist; + struct cmd *cmd; + struct pollfd pfd; + enum msgtype msg; + struct passwd *pw; + struct options *so, *wo; + struct keylist *keylist; + struct imsgbuf *ibuf; + char *s, *shellcmd, *path, *label, *home, *cause; + char cwd[MAXPATHLEN], **var; + void *buf; + size_t len; + int nfds, retcode, opt, flags, cmdflags = 0; flags = 0; shellcmd = label = path = NULL; @@ -518,19 +556,17 @@ main(int argc, char **argv) cmd_list_free(cmdlist); } - memset(&cctx, 0, sizeof cctx); - if (client_init(path, &cctx, cmdflags, flags) != 0) + if ((ibuf = client_init(path, cmdflags, flags)) == NULL) exit(1); xfree(path); - client_write_server(&cctx, msg, buf, len); - memset(buf, 0, len); + imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len); retcode = 0; for (;;) { - pfd.fd = cctx.ibuf.fd; + pfd.fd = ibuf->fd; pfd.events = POLLIN; - if (cctx.ibuf.w.queued != 0) + if (ibuf->w.queued != 0) pfd.events |= POLLOUT; if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { @@ -545,12 +581,12 @@ main(int argc, char **argv) fatalx("socket error"); if (pfd.revents & POLLIN) { - if (dispatch_imsg(&cctx, shellcmd, &retcode) != 0) + if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0) break; } if (pfd.revents & POLLOUT) { - if (msgbuf_write(&cctx.ibuf.w) < 0) + if (msgbuf_write(&ibuf->w) < 0) fatalx("msgbuf_write failed"); } } @@ -562,18 +598,18 @@ main(int argc, char **argv) } int -dispatch_imsg(struct client_ctx *cctx, const char *shellcmd, int *retcode) +dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode) { struct imsg imsg; ssize_t n, datalen; struct msg_print_data printdata; struct msg_shell_data shelldata; - if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) + if ((n = imsg_read(ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); for (;;) { - if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) + if ((n = imsg_get(ibuf, &imsg)) == -1) fatalx("imsg_get failed"); if (n == 0) return (0); @@ -601,8 +637,7 @@ dispatch_imsg(struct client_ctx *cctx, const char *shellcmd, int *retcode) if (datalen != 0) fatalx("bad MSG_READY size"); - *retcode = client_main(cctx); - return (-1); + client_main(); /* doesn't return */ case MSG_VERSION: if (datalen != 0) fatalx("bad MSG_VERSION size"); diff --git a/tmux.h b/tmux.h index 0e89a135..e97d4aaa 100644 --- a/tmux.h +++ b/tmux.h @@ -1052,19 +1052,6 @@ struct client { }; ARRAY_DECL(clients, struct client *); -/* Client context. */ -struct client_ctx { - struct imsgbuf ibuf; - - enum { - CCTX_DETACH, - CCTX_EXIT, - CCTX_DIED, - CCTX_SHUTDOWN - } exittype; - const char *errstr; -}; - /* Key/command line command. */ struct cmd_ctx { /* @@ -1503,14 +1490,8 @@ void cmd_buffer_free(struct cmd *); size_t cmd_buffer_print(struct cmd *, char *, size_t); /* client.c */ -int client_init(char *, struct client_ctx *, int, int); -int client_main(struct client_ctx *); -int client_msg_dispatch(struct client_ctx *); - -/* client-fn.c */ -void client_write_server(struct client_ctx *, enum msgtype, void *, size_t); -void client_fill_session(struct msg_command_data *); -void client_suspend(void); +struct imsgbuf *client_init(char *, int, int); +__dead void client_main(void); /* key-bindings.c */ extern struct key_bindings key_bindings;