Client tidying: get rid of client_ctx struct in favour of two variables in

client.c, and move the functions in client-fn.c into other files.
This commit is contained in:
Nicholas Marriott 2009-10-21 20:11:47 +00:00
parent 59e667906f
commit 90ad041fa5
5 changed files with 140 additions and 216 deletions

View File

@ -1,7 +1,7 @@
# $OpenBSD$ # $OpenBSD$
PROG= tmux 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 \ 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-break-pane.c cmd-choose-session.c cmd-choose-window.c \
cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \ cmd-clear-history.c cmd-clock-mode.c cmd-command-prompt.c \

View File

@ -1,90 +0,0 @@
/* $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 <stdlib.h>
#include <string.h>
#include <unistd.h>
#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);
}

148
client.c
View File

@ -33,10 +33,16 @@
#include "tmux.h" #include "tmux.h"
void client_send_environ(struct client_ctx *); struct imsgbuf client_ibuf;
const char *client_exitmsg;
int void client_send_environ(void);
client_init(char *path, struct client_ctx *cctx, int cmdflags, int flags) 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 sockaddr_un sa;
struct stat sb; struct stat sb;
@ -93,10 +99,10 @@ server_started:
fatal("fcntl failed"); fatal("fcntl failed");
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("fcntl failed"); fatal("fcntl failed");
imsg_init(&cctx->ibuf, fd); imsg_init(&client_ibuf, fd);
if (cmdflags & CMD_SENDENVIRON) if (cmdflags & CMD_SENDENVIRON)
client_send_environ(cctx); client_send_environ();
if (isatty(STDIN_FILENO)) { if (isatty(STDIN_FILENO)) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)"); fatal("ioctl(TIOCGWINSZ)");
@ -114,23 +120,23 @@ server_started:
if ((fd2 = dup(STDIN_FILENO)) == -1) if ((fd2 = dup(STDIN_FILENO)) == -1)
fatal("dup failed"); fatal("dup failed");
imsg_compose(&cctx->ibuf, MSG_IDENTIFY, imsg_compose(&client_ibuf, MSG_IDENTIFY,
PROTOCOL_VERSION, -1, fd2, &data, sizeof data); PROTOCOL_VERSION, -1, fd2, &data, sizeof data);
} }
return (0); return (&client_ibuf);
start_failed: start_failed:
log_warnx("server failed to start"); log_warnx("server failed to start");
return (1); return (NULL);
not_found: not_found:
log_warn("server not found"); log_warn("server not found");
return (1); return (NULL);
} }
void void
client_send_environ(struct client_ctx *cctx) client_send_environ(void)
{ {
char **var; char **var;
struct msg_environ_data data; struct msg_environ_data data;
@ -138,12 +144,18 @@ client_send_environ(struct client_ctx *cctx)
for (var = environ; *var != NULL; var++) { for (var = environ; *var != NULL; var++) {
if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var) if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
continue; continue;
client_write_server(cctx, MSG_ENVIRON, &data, sizeof data); client_write_server(MSG_ENVIRON, &data, sizeof data);
} }
} }
int void
client_main(struct client_ctx *cctx) 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; struct pollfd pfd;
int n, nfds; int n, nfds;
@ -158,29 +170,31 @@ client_main(struct client_ctx *cctx)
* MSG_READY switched to here. Process anything outstanding now so poll * MSG_READY switched to here. Process anything outstanding now so poll
* doesn't hang waiting for messages that have already arrived. * doesn't hang waiting for messages that have already arrived.
*/ */
if (client_msg_dispatch(cctx) != 0) if (client_dispatch() != 0)
goto out; goto out;
for (;;) { for (;;) {
if (sigterm) if (sigterm) {
client_write_server(cctx, MSG_EXITING, NULL, 0); client_exitmsg = "terminated";
client_write_server(MSG_EXITING, NULL, 0);
}
if (sigchld) { if (sigchld) {
waitpid(WAIT_ANY, NULL, WNOHANG); waitpid(WAIT_ANY, NULL, WNOHANG);
sigchld = 0; sigchld = 0;
} }
if (sigwinch) { if (sigwinch) {
client_write_server(cctx, MSG_RESIZE, NULL, 0); client_write_server(MSG_RESIZE, NULL, 0);
sigwinch = 0; sigwinch = 0;
} }
if (sigcont) { if (sigcont) {
siginit(); siginit();
client_write_server(cctx, MSG_WAKEUP, NULL, 0); client_write_server(MSG_WAKEUP, NULL, 0);
sigcont = 0; sigcont = 0;
} }
pfd.fd = cctx->ibuf.fd; pfd.fd = client_ibuf.fd;
pfd.events = POLLIN; pfd.events = POLLIN;
if (cctx->ibuf.w.queued > 0) if (client_ibuf.w.queued > 0)
pfd.events |= POLLOUT; pfd.events |= POLLOUT;
if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
@ -195,67 +209,41 @@ client_main(struct client_ctx *cctx)
fatalx("socket error"); fatalx("socket error");
if (pfd.revents & POLLIN) { if (pfd.revents & POLLIN) {
if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) { if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) {
cctx->exittype = CCTX_DIED; client_exitmsg = "lost server";
break; break;
} }
if (client_msg_dispatch(cctx) != 0) if (client_dispatch() != 0)
break; break;
} }
if (pfd.revents & POLLOUT) { if (pfd.revents & POLLOUT) {
if (msgbuf_write(&cctx->ibuf.w) < 0) { if (msgbuf_write(&client_ibuf.w) < 0) {
cctx->exittype = CCTX_DIED; client_exitmsg = "lost server";
break; break;
} }
} }
} }
out: out:
/* /* Print the exit message, if any, and exit. */
* Print exit status message, unless running as a login shell where it if (client_exitmsg != NULL) {
* 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) if (!login_shell)
printf("[server exited]\n"); printf("[%s]\n", client_exitmsg);
return (0); exit(1);
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:
if (!login_shell)
printf("[detached]\n");
return (0);
default:
printf("[unknown error]\n");
return (1);
} }
exit(0);
} }
int int
client_msg_dispatch(struct client_ctx *cctx) client_dispatch(void)
{ {
struct imsg imsg; struct imsg imsg;
struct msg_print_data printdata;
struct msg_lock_data lockdata; struct msg_lock_data lockdata;
ssize_t n, datalen; ssize_t n, datalen;
for (;;) { for (;;) {
if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed"); fatalx("imsg_get failed");
if (n == 0) if (n == 0)
return (0); return (0);
@ -266,25 +254,15 @@ client_msg_dispatch(struct client_ctx *cctx)
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_DETACH size"); fatalx("bad MSG_DETACH size");
client_write_server(cctx, MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_DETACH; client_exitmsg = "detached";
break; 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: case MSG_EXIT:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_EXIT size"); fatalx("bad MSG_EXIT size");
client_write_server(cctx, MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_EXIT; client_exitmsg = "exited";
break; break;
case MSG_EXITED: case MSG_EXITED:
if (datalen != 0) if (datalen != 0)
@ -296,8 +274,8 @@ client_msg_dispatch(struct client_ctx *cctx)
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_SHUTDOWN size"); fatalx("bad MSG_SHUTDOWN size");
client_write_server(cctx, MSG_EXITING, NULL, 0); client_write_server(MSG_EXITING, NULL, 0);
cctx->exittype = CCTX_SHUTDOWN; client_exitmsg = "server exited";
break; break;
case MSG_SUSPEND: case MSG_SUSPEND:
if (datalen != 0) if (datalen != 0)
@ -312,7 +290,7 @@ client_msg_dispatch(struct client_ctx *cctx)
lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0'; lockdata.cmd[(sizeof lockdata.cmd) - 1] = '\0';
system(lockdata.cmd); system(lockdata.cmd);
client_write_server(cctx, MSG_UNLOCK, NULL, 0); client_write_server(MSG_UNLOCK, NULL, 0);
break; break;
default: default:
fatalx("unexpected message"); fatalx("unexpected message");
@ -321,3 +299,23 @@ client_msg_dispatch(struct client_ctx *cctx)
imsg_free(&imsg); 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);
}

71
tmux.c
View File

@ -53,9 +53,10 @@ char *socket_path;
int login_shell; int login_shell;
__dead void usage(void); __dead void usage(void);
void fill_session(struct msg_command_data *);
char *makesockpath(const char *); char *makesockpath(const char *);
int prepare_cmd(enum msgtype *, void **, size_t *, int, 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 shell_exec(const char *, const char *);
__dead void __dead void
@ -215,6 +216,44 @@ areshell(const char *shell)
return (0); 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 * char *
makesockpath(const char *label) 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; static struct msg_command_data cmddata;
client_fill_session(&cmddata); fill_session(&cmddata);
cmddata.argc = argc; cmddata.argc = argc;
if (cmd_pack_argv(argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) { if (cmd_pack_argv(argc, argv, cmddata.argv, sizeof cmddata.argv) != 0) {
@ -266,7 +305,6 @@ prepare_cmd(enum msgtype *msg, void **buf, size_t *len, int argc, char **argv)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
struct client_ctx cctx;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd *cmd; struct cmd *cmd;
struct pollfd pfd; struct pollfd pfd;
@ -274,12 +312,12 @@ main(int argc, char **argv)
struct passwd *pw; struct passwd *pw;
struct options *so, *wo; struct options *so, *wo;
struct keylist *keylist; struct keylist *keylist;
struct imsgbuf *ibuf;
char *s, *shellcmd, *path, *label, *home, *cause; char *s, *shellcmd, *path, *label, *home, *cause;
char cwd[MAXPATHLEN], **var; char cwd[MAXPATHLEN], **var;
void *buf; void *buf;
size_t len; size_t len;
int retcode, opt, flags, cmdflags = 0; int nfds, retcode, opt, flags, cmdflags = 0;
int nfds;
flags = 0; flags = 0;
shellcmd = label = path = NULL; shellcmd = label = path = NULL;
@ -518,19 +556,17 @@ main(int argc, char **argv)
cmd_list_free(cmdlist); cmd_list_free(cmdlist);
} }
memset(&cctx, 0, sizeof cctx); if ((ibuf = client_init(path, cmdflags, flags)) == NULL)
if (client_init(path, &cctx, cmdflags, flags) != 0)
exit(1); exit(1);
xfree(path); xfree(path);
client_write_server(&cctx, msg, buf, len); imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
memset(buf, 0, len);
retcode = 0; retcode = 0;
for (;;) { for (;;) {
pfd.fd = cctx.ibuf.fd; pfd.fd = ibuf->fd;
pfd.events = POLLIN; pfd.events = POLLIN;
if (cctx.ibuf.w.queued != 0) if (ibuf->w.queued != 0)
pfd.events |= POLLOUT; pfd.events |= POLLOUT;
if ((nfds = poll(&pfd, 1, INFTIM)) == -1) { if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
@ -545,12 +581,12 @@ main(int argc, char **argv)
fatalx("socket error"); fatalx("socket error");
if (pfd.revents & POLLIN) { if (pfd.revents & POLLIN) {
if (dispatch_imsg(&cctx, shellcmd, &retcode) != 0) if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0)
break; break;
} }
if (pfd.revents & POLLOUT) { if (pfd.revents & POLLOUT) {
if (msgbuf_write(&cctx.ibuf.w) < 0) if (msgbuf_write(&ibuf->w) < 0)
fatalx("msgbuf_write failed"); fatalx("msgbuf_write failed");
} }
} }
@ -562,18 +598,18 @@ main(int argc, char **argv)
} }
int 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; struct imsg imsg;
ssize_t n, datalen; ssize_t n, datalen;
struct msg_print_data printdata; struct msg_print_data printdata;
struct msg_shell_data shelldata; 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"); fatalx("imsg_read failed");
for (;;) { for (;;) {
if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1) if ((n = imsg_get(ibuf, &imsg)) == -1)
fatalx("imsg_get failed"); fatalx("imsg_get failed");
if (n == 0) if (n == 0)
return (0); return (0);
@ -601,8 +637,7 @@ dispatch_imsg(struct client_ctx *cctx, const char *shellcmd, int *retcode)
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_READY size"); fatalx("bad MSG_READY size");
*retcode = client_main(cctx); client_main(); /* doesn't return */
return (-1);
case MSG_VERSION: case MSG_VERSION:
if (datalen != 0) if (datalen != 0)
fatalx("bad MSG_VERSION size"); fatalx("bad MSG_VERSION size");

23
tmux.h
View File

@ -1052,19 +1052,6 @@ struct client {
}; };
ARRAY_DECL(clients, 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. */ /* Key/command line command. */
struct cmd_ctx { struct cmd_ctx {
/* /*
@ -1503,14 +1490,8 @@ void cmd_buffer_free(struct cmd *);
size_t cmd_buffer_print(struct cmd *, char *, size_t); size_t cmd_buffer_print(struct cmd *, char *, size_t);
/* client.c */ /* client.c */
int client_init(char *, struct client_ctx *, int, int); struct imsgbuf *client_init(char *, int, int);
int client_main(struct client_ctx *); __dead void client_main(void);
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);
/* key-bindings.c */ /* key-bindings.c */
extern struct key_bindings key_bindings; extern struct key_bindings key_bindings;