mirror of
https://github.com/tmux/tmux.git
synced 2025-09-02 13:37:12 +00:00
Merge branch 'obsd-master'
Conflicts: log.c proc.c tmux.c
This commit is contained in:
94
client.c
94
client.c
@ -52,33 +52,35 @@ enum msgtype client_exittype;
|
||||
const char *client_exitsession;
|
||||
int client_attached;
|
||||
|
||||
__dead void client_exec(const char *);
|
||||
__dead void client_exec(const char *,const char *);
|
||||
int client_get_lock(char *);
|
||||
int client_connect(struct event_base *, char *, int);
|
||||
int client_connect(struct event_base *, const char *, int);
|
||||
void client_send_identify(const char *, const char *);
|
||||
void client_stdin_callback(int, short, void *);
|
||||
void client_write(int, const char *, size_t);
|
||||
void client_signal(int);
|
||||
void client_dispatch(struct imsg *, void *);
|
||||
void client_dispatch_attached(struct imsg *);
|
||||
void client_dispatch_wait(struct imsg *);
|
||||
void client_dispatch_wait(struct imsg *, const char *);
|
||||
const char *client_exit_message(void);
|
||||
|
||||
/*
|
||||
* Get server create lock. If already held then server start is happening in
|
||||
* another client, so block until the lock is released and return -1 to
|
||||
* retry. Ignore other errors - just continue and start the server without the
|
||||
* lock.
|
||||
* another client, so block until the lock is released and return -2 to
|
||||
* retry. Return -1 on failure to continue and start the server anyway.
|
||||
*/
|
||||
int
|
||||
client_get_lock(char *lockfile)
|
||||
{
|
||||
int lockfd;
|
||||
|
||||
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1)
|
||||
fatal("open failed");
|
||||
log_debug("lock file is %s", lockfile);
|
||||
|
||||
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
|
||||
log_debug("open failed: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
|
||||
log_debug("flock failed: %s", strerror(errno));
|
||||
if (errno != EAGAIN)
|
||||
@ -86,7 +88,7 @@ client_get_lock(char *lockfile)
|
||||
while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
|
||||
/* nothing */;
|
||||
close(lockfd);
|
||||
return (-1);
|
||||
return (-2);
|
||||
}
|
||||
log_debug("flock succeeded");
|
||||
|
||||
@ -95,7 +97,7 @@ client_get_lock(char *lockfile)
|
||||
|
||||
/* Connect client to server. */
|
||||
int
|
||||
client_connect(struct event_base *base, char *path, int start_server)
|
||||
client_connect(struct event_base *base, const char *path, int start_server)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
size_t size;
|
||||
@ -113,10 +115,10 @@ client_connect(struct event_base *base, char *path, int start_server)
|
||||
|
||||
retry:
|
||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
fatal("socket failed");
|
||||
return (-1);
|
||||
|
||||
log_debug("trying connect");
|
||||
if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
|
||||
if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
|
||||
log_debug("connect failed: %s", strerror(errno));
|
||||
if (errno != ECONNREFUSED && errno != ENOENT)
|
||||
goto failed;
|
||||
@ -126,12 +128,16 @@ retry:
|
||||
|
||||
if (!locked) {
|
||||
xasprintf(&lockfile, "%s.lock", path);
|
||||
if ((lockfd = client_get_lock(lockfile)) == -1) {
|
||||
log_debug("didn't get lock");
|
||||
if ((lockfd = client_get_lock(lockfile)) < 0) {
|
||||
log_debug("didn't get lock (%d)", lockfd);
|
||||
|
||||
free(lockfile);
|
||||
goto retry;
|
||||
lockfile = NULL;
|
||||
|
||||
if (lockfd == -2)
|
||||
goto retry;
|
||||
}
|
||||
log_debug("got lock");
|
||||
log_debug("got lock (%d)", lockfd);
|
||||
|
||||
/*
|
||||
* Always retry at least once, even if we got the lock,
|
||||
@ -143,7 +149,7 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (unlink(path) != 0 && errno != ENOENT) {
|
||||
if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
|
||||
free(lockfile);
|
||||
close(lockfd);
|
||||
return (-1);
|
||||
@ -151,7 +157,7 @@ retry:
|
||||
fd = server_start(base, lockfd, lockfile);
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
if (locked && lockfd >= 0) {
|
||||
free(lockfile);
|
||||
close(lockfd);
|
||||
}
|
||||
@ -206,7 +212,8 @@ client_exit_message(void)
|
||||
|
||||
/* Client main loop. */
|
||||
int
|
||||
client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
client_main(struct event_base *base, int argc, char **argv, int flags,
|
||||
const char *shellcmd)
|
||||
{
|
||||
struct cmd *cmd;
|
||||
struct cmd_list *cmdlist;
|
||||
@ -227,7 +234,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
|
||||
/* Set up the initial command. */
|
||||
cmdflags = 0;
|
||||
if (shell_cmd != NULL) {
|
||||
if (shellcmd != NULL) {
|
||||
msg = MSG_SHELL;
|
||||
cmdflags = CMD_STARTSERVER;
|
||||
} else if (argc == 0) {
|
||||
@ -254,6 +261,9 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
/* Create client process structure (starts logging). */
|
||||
client_proc = proc_start("client", base, 0, client_signal);
|
||||
|
||||
/* Initialize the client socket and start the server. */
|
||||
fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
|
||||
if (fd == -1) {
|
||||
@ -266,10 +276,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Build process state. */
|
||||
client_proc = proc_start("client", base, 0, client_signal);
|
||||
client_peer = proc_add_peer(client_proc, fd, client_dispatch, NULL);
|
||||
client_peer = proc_add_peer(client_proc, fd, client_dispatch,
|
||||
(void *)shellcmd);
|
||||
|
||||
/* Save these before pledge(). */
|
||||
if ((cwd = getcwd(path, sizeof path)) == NULL) {
|
||||
@ -304,11 +312,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
|
||||
client_stdin_callback, NULL);
|
||||
if (client_flags & CLIENT_CONTROLCONTROL) {
|
||||
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0) {
|
||||
fprintf(stderr, "tcgetattr failed: %s\n",
|
||||
strerror(errno));
|
||||
return (1);
|
||||
}
|
||||
if (tcgetattr(STDIN_FILENO, &saved_tio) != 0)
|
||||
fatal("tcgetattr failed");
|
||||
cfmakeraw(&tio);
|
||||
tio.c_iflag = ICRNL|IXANY;
|
||||
tio.c_oflag = OPOST|ONLCR;
|
||||
@ -371,7 +376,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags)
|
||||
printf("%%exit\n");
|
||||
printf("\033\\");
|
||||
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
|
||||
}
|
||||
} else if (client_exitreason != CLIENT_EXIT_NONE)
|
||||
fprintf(stderr, "%s\n", client_exit_message());
|
||||
setblocking(STDIN_FILENO, 1);
|
||||
return (client_exitval);
|
||||
}
|
||||
@ -392,7 +398,8 @@ client_send_identify(const char *ttynam, const char *cwd)
|
||||
s = "";
|
||||
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
|
||||
|
||||
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, strlen(ttynam) + 1);
|
||||
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
|
||||
strlen(ttynam) + 1);
|
||||
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
|
||||
|
||||
if ((fd = dup(STDIN_FILENO)) == -1)
|
||||
@ -404,8 +411,9 @@ client_send_identify(const char *ttynam, const char *cwd)
|
||||
|
||||
for (ss = environ; *ss != NULL; ss++) {
|
||||
sslen = strlen(*ss) + 1;
|
||||
if (sslen <= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
|
||||
proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
|
||||
if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
|
||||
continue;
|
||||
proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
|
||||
}
|
||||
|
||||
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
|
||||
@ -447,12 +455,12 @@ client_write(int fd, const char *data, size_t size)
|
||||
|
||||
/* Run command in shell; used for -c. */
|
||||
__dead void
|
||||
client_exec(const char *shell)
|
||||
client_exec(const char *shell, const char *shellcmd)
|
||||
{
|
||||
const char *name, *ptr;
|
||||
char *argv0;
|
||||
|
||||
log_debug("shell %s, command %s", shell, shell_cmd);
|
||||
log_debug("shell %s, command %s", shell, shellcmd);
|
||||
|
||||
ptr = strrchr(shell, '/');
|
||||
if (ptr != NULL && *(ptr + 1) != '\0')
|
||||
@ -470,7 +478,7 @@ client_exec(const char *shell)
|
||||
setblocking(STDERR_FILENO, 1);
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
execl(shell, argv0, "-c", shell_cmd, (char *) NULL);
|
||||
execl(shell, argv0, "-c", shellcmd, (char *) NULL);
|
||||
fatal("execl failed");
|
||||
}
|
||||
|
||||
@ -516,20 +524,24 @@ client_signal(int sig)
|
||||
|
||||
/* Callback for client read events. */
|
||||
void
|
||||
client_dispatch(struct imsg *imsg, __unused void *arg)
|
||||
client_dispatch(struct imsg *imsg, void *arg)
|
||||
{
|
||||
if (imsg == NULL) {
|
||||
client_exitreason = CLIENT_EXIT_LOST_SERVER;
|
||||
client_exitval = 1;
|
||||
} else if (client_attached)
|
||||
proc_exit(client_proc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_attached)
|
||||
client_dispatch_attached(imsg);
|
||||
else
|
||||
client_dispatch_wait(imsg);
|
||||
client_dispatch_wait(imsg, arg);
|
||||
}
|
||||
|
||||
/* Dispatch imsgs when in wait state (before MSG_READY). */
|
||||
void
|
||||
client_dispatch_wait(struct imsg *imsg)
|
||||
client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
|
||||
{
|
||||
char *data;
|
||||
ssize_t datalen;
|
||||
@ -611,7 +623,7 @@ client_dispatch_wait(struct imsg *imsg)
|
||||
fatalx("bad MSG_SHELL string");
|
||||
|
||||
clear_signals(0);
|
||||
client_exec(data);
|
||||
client_exec(data, shellcmd);
|
||||
/* NOTREACHED */
|
||||
case MSG_DETACH:
|
||||
case MSG_DETACHKILL:
|
||||
|
Reference in New Issue
Block a user