version 1.24, 2009/10/13 13:15:26 |
version 1.25, 2009/10/21 20:11:47 |
|
|
|
|
#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; |
|
|
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)"); |
|
|
|
|
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; |
|
|
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; |
|
|
|
|
* 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) { |
|
|
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) |
|
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: |
|
if (!login_shell) |
if (!login_shell) |
printf("[detached]\n"); |
printf("[%s]\n", client_exitmsg); |
return (0); |
exit(1); |
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); |
|
|
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) |
|
|
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) |
|
|
|
|
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"); |
|
|
|
|
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); |
} |
} |