version 1.92, 2015/08/30 22:19:07 |
version 1.93, 2015/08/30 22:40:25 |
|
|
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
|
int client_flags; |
struct imsgbuf client_ibuf; |
struct imsgbuf client_ibuf; |
struct event client_event; |
struct event client_event; |
struct event client_stdin; |
struct event client_stdin; |
|
|
const char *client_exitsession; |
const char *client_exitsession; |
int client_attached; |
int client_attached; |
|
|
|
__dead void client_exec(const char *); |
int client_get_lock(char *); |
int client_get_lock(char *); |
int client_connect(struct event_base *, char *, int); |
int client_connect(struct event_base *, char *, int); |
void client_send_identify(int); |
void client_send_identify(void); |
int client_write_one(enum msgtype, int, const void *, size_t); |
int client_write_one(enum msgtype, int, const void *, size_t); |
int client_write_server(enum msgtype, const void *, size_t); |
int client_write_server(enum msgtype, const void *, size_t); |
void client_update_event(void); |
void client_update_event(void); |
|
|
void client_write(int, const char *, size_t); |
void client_write(int, const char *, size_t); |
void client_callback(int, short, void *); |
void client_callback(int, short, void *); |
int client_dispatch_attached(void); |
int client_dispatch_attached(void); |
int client_dispatch_wait(void *); |
int client_dispatch_wait(void); |
const char *client_exit_message(void); |
const char *client_exit_message(void); |
|
|
/* |
/* |
|
|
struct termios tio, saved_tio; |
struct termios tio, saved_tio; |
size_t size; |
size_t size; |
|
|
|
/* Save the flags. */ |
|
client_flags = flags; |
|
|
/* Set up the initial command. */ |
/* Set up the initial command. */ |
cmdflags = 0; |
cmdflags = 0; |
if (shell_cmd != NULL) { |
if (shell_cmd != NULL) { |
|
|
|
|
/* Create imsg. */ |
/* Create imsg. */ |
imsg_init(&client_ibuf, fd); |
imsg_init(&client_ibuf, fd); |
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd); |
event_set(&client_event, fd, EV_READ, client_callback, NULL); |
|
|
/* Create stdin handler. */ |
/* Create stdin handler. */ |
setblocking(STDIN_FILENO, 0); |
setblocking(STDIN_FILENO, 0); |
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, |
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST, |
client_stdin_callback, NULL); |
client_stdin_callback, NULL); |
if (flags & CLIENT_CONTROLCONTROL) { |
if (client_flags & CLIENT_CONTROLCONTROL) { |
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { |
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) { |
fprintf(stderr, "tcgetattr failed: %s\n", |
fprintf(stderr, "tcgetattr failed: %s\n", |
strerror(errno)); |
strerror(errno)); |
|
|
} |
} |
|
|
/* Send identify messages. */ |
/* Send identify messages. */ |
client_send_identify(flags); |
client_send_identify(); |
|
|
/* Send first command. */ |
/* Send first command. */ |
if (msg == MSG_COMMAND) { |
if (msg == MSG_COMMAND) { |
|
|
|
|
/* Print the exit message, if any, and exit. */ |
/* Print the exit message, if any, and exit. */ |
if (client_attached) { |
if (client_attached) { |
if (client_exitreason != CLIENT_EXIT_NONE && !login_shell) |
if (client_exitreason != CLIENT_EXIT_NONE) |
printf("[%s]\n", client_exit_message()); |
printf("[%s]\n", client_exit_message()); |
|
|
ppid = getppid(); |
ppid = getppid(); |
if (client_exittype == MSG_DETACHKILL && ppid > 1) |
if (client_exittype == MSG_DETACHKILL && ppid > 1) |
kill(ppid, SIGHUP); |
kill(ppid, SIGHUP); |
} else if (flags & CLIENT_CONTROLCONTROL) { |
} else if (client_flags & CLIENT_CONTROLCONTROL) { |
if (client_exitreason != CLIENT_EXIT_NONE) |
if (client_exitreason != CLIENT_EXIT_NONE) |
printf("%%exit %s\n", client_exit_message()); |
printf("%%exit %s\n", client_exit_message()); |
else |
else |
|
|
|
|
/* Send identify messages to server. */ |
/* Send identify messages to server. */ |
void |
void |
client_send_identify(int flags) |
client_send_identify(void) |
{ |
{ |
const char *s; |
const char *s; |
char **ss; |
char **ss; |
size_t sslen; |
size_t sslen; |
int fd; |
int fd, flags = client_flags; |
pid_t pid; |
pid_t pid; |
|
|
client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); |
client_write_one(MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); |
|
|
events = EV_READ; |
events = EV_READ; |
if (client_ibuf.w.queued > 0) |
if (client_ibuf.w.queued > 0) |
events |= EV_WRITE; |
events |= EV_WRITE; |
event_set( |
event_set(&client_event, client_ibuf.fd, events, client_callback, NULL); |
&client_event, client_ibuf.fd, events, client_callback, shell_cmd); |
|
event_add(&client_event, NULL); |
event_add(&client_event, NULL); |
} |
} |
|
|
/* Callback to handle signals in the client. */ |
/* Callback to handle signals in the client. */ |
void |
void |
client_signal(int sig, unused short events, unused void *data) |
client_signal(int sig, unused short events, unused void *arg) |
{ |
{ |
struct sigaction sigact; |
struct sigaction sigact; |
int status; |
int status; |
|
|
|
|
/* Callback for client imsg read events. */ |
/* Callback for client imsg read events. */ |
void |
void |
client_callback(unused int fd, short events, void *data) |
client_callback(unused int fd, short events, unused void *arg) |
{ |
{ |
ssize_t n; |
ssize_t n; |
int retval; |
int retval; |
|
|
if (client_attached) |
if (client_attached) |
retval = client_dispatch_attached(); |
retval = client_dispatch_attached(); |
else |
else |
retval = client_dispatch_wait(data); |
retval = client_dispatch_wait(); |
if (retval != 0) { |
if (retval != 0) { |
event_loopexit(NULL); |
event_loopexit(NULL); |
return; |
return; |
|
|
|
|
/* Callback for client stdin read events. */ |
/* Callback for client stdin read events. */ |
void |
void |
client_stdin_callback(unused int fd, unused short events, unused void *data1) |
client_stdin_callback(unused int fd, unused short events, unused void *arg) |
{ |
{ |
struct msg_stdin_data data; |
struct msg_stdin_data data; |
|
|
|
|
} |
} |
} |
} |
|
|
|
/* Run command in shell; used for -c. */ |
|
__dead void |
|
client_exec(const char *shell) |
|
{ |
|
const char *name, *ptr; |
|
char *argv0; |
|
|
|
log_debug("shell %s, command %s", shell, shell_cmd); |
|
|
|
ptr = strrchr(shell, '/'); |
|
if (ptr != NULL && *(ptr + 1) != '\0') |
|
name = ptr + 1; |
|
else |
|
name = shell; |
|
if (client_flags & CLIENT_LOGIN) |
|
xasprintf(&argv0, "-%s", name); |
|
else |
|
xasprintf(&argv0, "%s", name); |
|
setenv("SHELL", shell, 1); |
|
|
|
setblocking(STDIN_FILENO, 1); |
|
setblocking(STDOUT_FILENO, 1); |
|
setblocking(STDERR_FILENO, 1); |
|
closefrom(STDERR_FILENO + 1); |
|
|
|
execl(shell, argv0, "-c", shell_cmd, (char *) NULL); |
|
fatal("execl failed"); |
|
} |
|
|
/* Dispatch imsgs when in wait state (before MSG_READY). */ |
/* Dispatch imsgs when in wait state (before MSG_READY). */ |
int |
int |
client_dispatch_wait(void *data0) |
client_dispatch_wait(void) |
{ |
{ |
struct imsg imsg; |
struct imsg imsg; |
char *data; |
char *data; |
|
|
fatalx("bad MSG_SHELL string"); |
fatalx("bad MSG_SHELL string"); |
|
|
clear_signals(0); |
clear_signals(0); |
shell_exec(data, data0); |
client_exec(data); |
/* NOTREACHED */ |
/* NOTREACHED */ |
case MSG_DETACH: |
case MSG_DETACH: |
case MSG_DETACHKILL: |
case MSG_DETACHKILL: |