mirror of
https://github.com/tmate-io/tmate.git
synced 2024-11-08 01:04:06 +01:00
Sync OpenBSD patchset 491:
Initial changes to move tmux to libevent. This moves the client-side loops are pretty much fully over to event-based only (tmux.c and client.c) but server-side (server.c and friends) treats libevent as a sort of clever poll, waking up after every event to run various things. Moving the server stuff over to bufferevents and timers and so on will come later.
This commit is contained in:
parent
5ce49941fb
commit
dd36982ad5
@ -1,4 +1,4 @@
|
||||
/* $Id: buffer-poll.c,v 1.18 2009-10-23 17:49:47 tcunha Exp $ */
|
||||
/* $Id: buffer-poll.c,v 1.19 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@ -29,9 +30,7 @@ buffer_poll(int fd, int events, struct buffer *in, struct buffer *out)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
if (events & (POLLERR|POLLNVAL))
|
||||
return (-1);
|
||||
if (in != NULL && events & POLLIN) {
|
||||
if (in != NULL && events & EV_READ) {
|
||||
buffer_ensure(in, BUFSIZ);
|
||||
n = read(fd, BUFFER_IN(in), BUFFER_FREE(in));
|
||||
if (n == 0)
|
||||
@ -41,9 +40,8 @@ buffer_poll(int fd, int events, struct buffer *in, struct buffer *out)
|
||||
return (-1);
|
||||
} else
|
||||
buffer_add(in, n);
|
||||
} else if (events & POLLHUP)
|
||||
return (-1);
|
||||
if (out != NULL && BUFFER_USED(out) > 0 && events & POLLOUT) {
|
||||
}
|
||||
if (out != NULL && BUFFER_USED(out) > 0 && events & EV_WRITE) {
|
||||
n = write(fd, BUFFER_OUT(out), BUFFER_USED(out));
|
||||
if (n == -1) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
|
216
client.c
216
client.c
@ -1,4 +1,4 @@
|
||||
/* $Id: client.c,v 1.84 2009-11-02 21:41:16 tcunha Exp $ */
|
||||
/* $Id: client.c,v 1.85 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -24,6 +24,7 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
@ -34,13 +35,15 @@
|
||||
#include "tmux.h"
|
||||
|
||||
struct imsgbuf client_ibuf;
|
||||
struct event client_event;
|
||||
const char *client_exitmsg;
|
||||
|
||||
void client_send_identify(int);
|
||||
void client_send_environ(void);
|
||||
void client_write_server(enum msgtype, void *, size_t);
|
||||
int client_dispatch(void);
|
||||
void client_suspend(void);
|
||||
void client_send_identify(int);
|
||||
void client_send_environ(void);
|
||||
void client_write_server(enum msgtype, void *, size_t);
|
||||
void client_signal(int, short, void *);
|
||||
void client_callback(int, short, void *);
|
||||
int client_dispatch(void);
|
||||
|
||||
struct imsgbuf *
|
||||
client_init(char *path, int cmdflags, int flags)
|
||||
@ -158,76 +161,54 @@ client_write_server(enum msgtype type, void *buf, size_t len)
|
||||
__dead void
|
||||
client_main(void)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int n, nfds;
|
||||
|
||||
siginit();
|
||||
struct event ev_sigcont, ev_sigterm, ev_sigwinch;
|
||||
struct sigaction sigact;
|
||||
short events;
|
||||
|
||||
logfile("client");
|
||||
|
||||
/* Note: event_init() has already been called. */
|
||||
|
||||
/* Set up signals. */
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&ev_sigcont, SIGCONT, client_signal, NULL);
|
||||
signal_add(&ev_sigcont, NULL);
|
||||
signal_set(&ev_sigterm, SIGTERM, client_signal, NULL);
|
||||
signal_add(&ev_sigterm, NULL);
|
||||
signal_set(&ev_sigwinch, SIGWINCH, client_signal, NULL);
|
||||
signal_add(&ev_sigwinch, NULL);
|
||||
|
||||
/*
|
||||
* imsg_read in the first client poll loop (before the terminal has
|
||||
* been initialiased) may have read messages into the buffer after the
|
||||
* MSG_READY switched to here. Process anything outstanding now so poll
|
||||
* doesn't hang waiting for messages that have already arrived.
|
||||
* been initialised) may have read messages into the buffer after the
|
||||
* MSG_READY switched to here. Process anything outstanding now to
|
||||
* avoid hanging waiting for messages that have already arrived.
|
||||
*/
|
||||
if (client_dispatch() != 0)
|
||||
goto out;
|
||||
|
||||
for (;;) {
|
||||
if (sigterm) {
|
||||
client_exitmsg = "terminated";
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
}
|
||||
if (sigchld) {
|
||||
sigchld = 0;
|
||||
waitpid(WAIT_ANY, NULL, WNOHANG);
|
||||
continue;
|
||||
}
|
||||
if (sigwinch) {
|
||||
sigwinch = 0;
|
||||
client_write_server(MSG_RESIZE, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
if (sigcont) {
|
||||
sigcont = 0;
|
||||
siginit();
|
||||
client_write_server(MSG_WAKEUP, NULL, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
pfd.fd = client_ibuf.fd;
|
||||
pfd.events = POLLIN;
|
||||
if (client_ibuf.w.queued > 0)
|
||||
pfd.events |= POLLOUT;
|
||||
|
||||
if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
fatal("poll failed");
|
||||
}
|
||||
if (nfds == 0)
|
||||
continue;
|
||||
|
||||
if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
|
||||
fatalx("socket error");
|
||||
|
||||
if (pfd.revents & POLLIN) {
|
||||
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0) {
|
||||
client_exitmsg = "lost server";
|
||||
break;
|
||||
}
|
||||
if (client_dispatch() != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pfd.revents & POLLOUT) {
|
||||
if (msgbuf_write(&client_ibuf.w) < 0) {
|
||||
client_exitmsg = "lost server";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Set up the client-server socket event. */
|
||||
events = EV_READ;
|
||||
if (client_ibuf.w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
|
||||
event_add(&client_event, NULL);
|
||||
|
||||
event_dispatch();
|
||||
|
||||
out:
|
||||
/* Print the exit message, if any, and exit. */
|
||||
@ -239,12 +220,78 @@ out:
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
client_signal(int sig, short events, unused void *data)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
client_exitmsg = "terminated";
|
||||
client_write_server(MSG_EXITING, NULL, 0);
|
||||
break;
|
||||
case SIGWINCH:
|
||||
client_write_server(MSG_RESIZE, NULL, 0);
|
||||
break;
|
||||
case SIGCONT:
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
client_write_server(MSG_WAKEUP, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
event_del(&client_event);
|
||||
events = EV_READ;
|
||||
if (client_ibuf.w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
|
||||
event_add(&client_event, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
client_callback(unused int fd, short events, unused void *data)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (events & EV_READ) {
|
||||
if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
|
||||
goto lost_server;
|
||||
if (client_dispatch() != 0) {
|
||||
event_loopexit(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
if (msgbuf_write(&client_ibuf.w) < 0)
|
||||
goto lost_server;
|
||||
}
|
||||
|
||||
event_del(&client_event);
|
||||
events = EV_READ;
|
||||
if (client_ibuf.w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_set(&client_event, client_ibuf.fd, events, client_callback, NULL);
|
||||
event_add(&client_event, NULL);
|
||||
|
||||
return;
|
||||
|
||||
lost_server:
|
||||
client_exitmsg = "lost server";
|
||||
event_loopexit(NULL);
|
||||
}
|
||||
|
||||
int
|
||||
client_dispatch(void)
|
||||
{
|
||||
struct imsg imsg;
|
||||
struct msg_lock_data lockdata;
|
||||
ssize_t n, datalen;
|
||||
struct imsg imsg;
|
||||
struct msg_lock_data lockdata;
|
||||
struct sigaction sigact;
|
||||
ssize_t n, datalen;
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
|
||||
@ -253,6 +300,7 @@ client_dispatch(void)
|
||||
return (0);
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
log_debug("client got %d", imsg.hdr.type);
|
||||
switch (imsg.hdr.type) {
|
||||
case MSG_DETACH:
|
||||
if (datalen != 0)
|
||||
@ -285,7 +333,13 @@ client_dispatch(void)
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_SUSPEND size");
|
||||
|
||||
client_suspend();
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
kill(getpid(), SIGTSTP);
|
||||
break;
|
||||
case MSG_LOCK:
|
||||
if (datalen != sizeof lockdata)
|
||||
@ -303,23 +357,3 @@ client_dispatch(void)
|
||||
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);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-kill-server.c,v 1.8 2009-07-28 22:12:16 tcunha Exp $ */
|
||||
/* $Id: cmd-kill-server.c,v 1.9 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -43,7 +43,7 @@ const struct cmd_entry cmd_kill_server_entry = {
|
||||
int
|
||||
cmd_kill_server_exec(unused struct cmd *self, unused struct cmd_ctx *ctx)
|
||||
{
|
||||
sigterm = 1;
|
||||
kill(getpid(), SIGTERM);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-pipe-pane.c,v 1.3 2009-10-23 17:26:40 tcunha Exp $ */
|
||||
/* $Id: cmd-pipe-pane.c,v 1.4 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -87,7 +87,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
case 0:
|
||||
/* Child process. */
|
||||
close(pipe_fd[0]);
|
||||
sigreset();
|
||||
server_signal_clear();
|
||||
|
||||
if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
|
||||
_exit(1);
|
||||
|
6
job.c
6
job.c
@ -1,4 +1,4 @@
|
||||
/* $Id: job.c,v 1.9 2009-11-02 21:38:26 tcunha Exp $ */
|
||||
/* $Id: job.c,v 1.10 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -86,6 +86,7 @@ job_add(struct jobs *jobs, int flags, struct client *c, const char *cmd,
|
||||
|
||||
job->fd = -1;
|
||||
job->out = buffer_create(BUFSIZ);
|
||||
memset(&job->event, 0, sizeof job->event);
|
||||
|
||||
job->callbackfn = callbackfn;
|
||||
job->freefn = freefn;
|
||||
@ -125,6 +126,7 @@ job_free(struct job *job)
|
||||
close(job->fd);
|
||||
if (job->out != NULL)
|
||||
buffer_destroy(job->out);
|
||||
event_del(&job->event);
|
||||
|
||||
xfree(job);
|
||||
}
|
||||
@ -146,7 +148,7 @@ job_run(struct job *job)
|
||||
case -1:
|
||||
return (-1);
|
||||
case 0: /* child */
|
||||
sigreset();
|
||||
server_signal_clear();
|
||||
/* XXX environ? */
|
||||
|
||||
if (dup2(out[1], STDOUT_FILENO) == -1)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: server-client.c,v 1.12 2009-11-04 22:46:25 tcunha Exp $ */
|
||||
/* $Id: server-client.c,v 1.13 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <event.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@ -133,7 +134,9 @@ server_client_lost(struct client *c)
|
||||
|
||||
close(c->ibuf.fd);
|
||||
imsg_clear(&c->ibuf);
|
||||
|
||||
event_del(&c->event);
|
||||
event_del(&c->tty.event);
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) {
|
||||
if (ARRAY_ITEM(&dead_clients, i) == NULL) {
|
||||
ARRAY_SET(&dead_clients, i, c);
|
||||
@ -161,25 +164,31 @@ server_client_prepare(void)
|
||||
|
||||
events = 0;
|
||||
if (!(c->flags & CLIENT_BAD))
|
||||
events |= POLLIN;
|
||||
events |= EV_READ;
|
||||
if (c->ibuf.w.queued > 0)
|
||||
events |= POLLOUT;
|
||||
server_poll_add(c->ibuf.fd, events, server_client_callback, c);
|
||||
events |= EV_WRITE;
|
||||
event_del(&c->event);
|
||||
event_set(&c->event,
|
||||
c->ibuf.fd, events, server_client_callback, c);
|
||||
event_add(&c->event, NULL);
|
||||
|
||||
if (c->tty.fd == -1)
|
||||
continue;
|
||||
if (c->flags & CLIENT_SUSPENDED || c->session == NULL)
|
||||
continue;
|
||||
events = POLLIN;
|
||||
events = EV_READ;
|
||||
if (BUFFER_USED(c->tty.out) > 0)
|
||||
events |= POLLOUT;
|
||||
server_poll_add(c->tty.fd, events, server_client_callback, c);
|
||||
events |= EV_WRITE;
|
||||
event_del(&c->tty.event);
|
||||
event_set(&c->tty.event,
|
||||
c->tty.fd, events, server_client_callback, c);
|
||||
event_add(&c->tty.event, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process a single client event. */
|
||||
void
|
||||
server_client_callback(int fd, int events, void *data)
|
||||
server_client_callback(int fd, short events, void *data)
|
||||
{
|
||||
struct client *c = data;
|
||||
|
||||
@ -187,10 +196,7 @@ server_client_callback(int fd, int events, void *data)
|
||||
return;
|
||||
|
||||
if (fd == c->ibuf.fd) {
|
||||
if (events & (POLLERR|POLLNVAL|POLLHUP))
|
||||
goto client_lost;
|
||||
|
||||
if (events & POLLOUT && msgbuf_write(&c->ibuf.w) < 0)
|
||||
if (events & EV_WRITE && msgbuf_write(&c->ibuf.w) < 0)
|
||||
goto client_lost;
|
||||
|
||||
if (c->flags & CLIENT_BAD) {
|
||||
@ -199,7 +205,7 @@ server_client_callback(int fd, int events, void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (events & POLLIN && server_client_msg_dispatch(c) != 0)
|
||||
if (events & EV_READ && server_client_msg_dispatch(c) != 0)
|
||||
goto client_lost;
|
||||
}
|
||||
|
||||
@ -210,7 +216,7 @@ server_client_callback(int fd, int events, void *data)
|
||||
if (buffer_poll(fd, events, c->tty.in, c->tty.out) != 0)
|
||||
goto client_lost;
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
|
||||
client_lost:
|
||||
@ -423,7 +429,7 @@ server_client_check_redraw(struct client *c)
|
||||
if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) {
|
||||
if (options_get_number(&s->options, "set-titles"))
|
||||
server_client_set_title(c);
|
||||
|
||||
|
||||
if (c->message_string != NULL)
|
||||
redraw = status_message_redraw(c);
|
||||
else if (c->prompt_string != NULL)
|
||||
|
12
server-job.c
12
server-job.c
@ -1,4 +1,4 @@
|
||||
/* $Id: server-job.c,v 1.3 2009-11-02 21:38:26 tcunha Exp $ */
|
||||
/* $Id: server-job.c,v 1.4 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <event.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@ -31,13 +32,16 @@ server_job_prepare(void)
|
||||
SLIST_FOREACH(job, &all_jobs, lentry) {
|
||||
if (job->fd == -1)
|
||||
continue;
|
||||
server_poll_add(job->fd, POLLIN, server_job_callback, job);
|
||||
event_del(&job->event);
|
||||
event_set(
|
||||
&job->event, job->fd, EV_READ, server_job_callback, job);
|
||||
event_add(&job->event, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process a single job event. */
|
||||
void
|
||||
server_job_callback(int fd, int events, void *data)
|
||||
server_job_callback(int fd, short events, void *data)
|
||||
{
|
||||
struct job *job = data;
|
||||
|
||||
@ -55,7 +59,7 @@ void
|
||||
server_job_loop(void)
|
||||
{
|
||||
struct job *job;
|
||||
|
||||
|
||||
restart:
|
||||
SLIST_FOREACH(job, &all_jobs, lentry) {
|
||||
if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: server-window.c,v 1.4 2009-11-04 22:47:29 tcunha Exp $ */
|
||||
/* $Id: server-window.c,v 1.5 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <event.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
@ -47,19 +48,23 @@ server_window_prepare(void)
|
||||
continue;
|
||||
events = 0;
|
||||
if (!server_window_backoff(wp))
|
||||
events |= POLLIN;
|
||||
events = EV_READ;
|
||||
if (BUFFER_USED(wp->out) > 0)
|
||||
events |= POLLOUT;
|
||||
server_poll_add(
|
||||
events |= EV_WRITE;
|
||||
event_del(&wp->event);
|
||||
event_set(&wp->event,
|
||||
wp->fd, events, server_window_callback, wp);
|
||||
event_add(&wp->event, NULL);
|
||||
|
||||
if (wp->pipe_fd == -1)
|
||||
continue;
|
||||
events = 0;
|
||||
if (BUFFER_USED(wp->pipe_buf) > 0)
|
||||
events |= POLLOUT;
|
||||
server_poll_add(
|
||||
events |= EV_WRITE;
|
||||
event_del(&wp->pipe_event);
|
||||
event_set(&wp->pipe_event,
|
||||
wp->pipe_fd, events, server_window_callback, wp);
|
||||
event_add(&wp->pipe_event, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -90,7 +95,7 @@ server_window_backoff(struct window_pane *wp)
|
||||
|
||||
/* Process a single window pane event. */
|
||||
void
|
||||
server_window_callback(int fd, int events, void *data)
|
||||
server_window_callback(int fd, short events, void *data)
|
||||
{
|
||||
struct window_pane *wp = data;
|
||||
|
||||
|
600
server.c
600
server.c
@ -1,4 +1,4 @@
|
||||
/* $Id: server.c,v 1.216 2009-11-04 22:42:31 tcunha Exp $ */
|
||||
/* $Id: server.c,v 1.217 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -24,6 +24,7 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
@ -44,112 +45,28 @@
|
||||
struct clients clients;
|
||||
struct clients dead_clients;
|
||||
|
||||
/* Mapping of a pollfd to an fd independent of its position in the array. */
|
||||
struct poll_item {
|
||||
int fd;
|
||||
int events;
|
||||
|
||||
void (*fn)(int, int, void *);
|
||||
void *data;
|
||||
|
||||
RB_ENTRY(poll_item) entry;
|
||||
};
|
||||
RB_HEAD(poll_items, poll_item) poll_items;
|
||||
|
||||
int server_poll_cmp(struct poll_item *, struct poll_item *);
|
||||
struct poll_item*server_poll_lookup(int);
|
||||
struct pollfd *server_poll_flatten(int *);
|
||||
void server_poll_dispatch(struct pollfd *, int);
|
||||
void server_poll_reset(void);
|
||||
RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp);
|
||||
RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp);
|
||||
int server_fd;
|
||||
int server_shutdown;
|
||||
struct event server_ev_accept;
|
||||
struct event server_ev_sigterm;
|
||||
struct event server_ev_sigusr1;
|
||||
struct event server_ev_sigchld;
|
||||
struct event server_ev_second;
|
||||
|
||||
int server_create_socket(void);
|
||||
void server_callback(int, int, void *);
|
||||
int server_main(int);
|
||||
void server_shutdown(void);
|
||||
void server_loop(void);
|
||||
int server_should_shutdown(void);
|
||||
void server_child_signal(void);
|
||||
void server_send_shutdown(void);
|
||||
void server_clean_dead(void);
|
||||
void server_second_timers(void);
|
||||
int server_update_socket(void);
|
||||
void server_accept_callback(int, short, void *);
|
||||
void server_signal_callback(int, short, void *);
|
||||
void server_child_signal(void);
|
||||
void server_child_exited(pid_t, int);
|
||||
void server_child_stopped(pid_t, int);
|
||||
void server_second_callback(int, short, void *);
|
||||
void server_lock_server(void);
|
||||
void server_lock_sessions(void);
|
||||
int server_update_socket(void);
|
||||
|
||||
int
|
||||
server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2)
|
||||
{
|
||||
return (pitem1->fd - pitem2->fd);
|
||||
}
|
||||
|
||||
void
|
||||
server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data)
|
||||
{
|
||||
struct poll_item *pitem;
|
||||
|
||||
pitem = xmalloc(sizeof *pitem);
|
||||
pitem->fd = fd;
|
||||
pitem->events = events;
|
||||
|
||||
pitem->fn = fn;
|
||||
pitem->data = data;
|
||||
|
||||
RB_INSERT(poll_items, &poll_items, pitem);
|
||||
}
|
||||
|
||||
struct poll_item *
|
||||
server_poll_lookup(int fd)
|
||||
{
|
||||
struct poll_item pitem;
|
||||
|
||||
pitem.fd = fd;
|
||||
return (RB_FIND(poll_items, &poll_items, &pitem));
|
||||
}
|
||||
|
||||
struct pollfd *
|
||||
server_poll_flatten(int *nfds)
|
||||
{
|
||||
struct poll_item *pitem;
|
||||
struct pollfd *pfds;
|
||||
|
||||
pfds = NULL;
|
||||
*nfds = 0;
|
||||
RB_FOREACH(pitem, poll_items, &poll_items) {
|
||||
pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds);
|
||||
pfds[*nfds].fd = pitem->fd;
|
||||
pfds[*nfds].events = pitem->events;
|
||||
(*nfds)++;
|
||||
}
|
||||
return (pfds);
|
||||
}
|
||||
|
||||
void
|
||||
server_poll_dispatch(struct pollfd *pfds, int nfds)
|
||||
{
|
||||
struct poll_item *pitem;
|
||||
struct pollfd *pfd;
|
||||
|
||||
while (nfds > 0) {
|
||||
pfd = &pfds[--nfds];
|
||||
if (pfd->revents != 0) {
|
||||
pitem = server_poll_lookup(pfd->fd);
|
||||
pitem->fn(pitem->fd, pfd->revents, pitem->data);
|
||||
}
|
||||
}
|
||||
xfree(pfds);
|
||||
}
|
||||
|
||||
void
|
||||
server_poll_reset(void)
|
||||
{
|
||||
struct poll_item *pitem;
|
||||
|
||||
while (!RB_EMPTY(&poll_items)) {
|
||||
pitem = RB_ROOT(&poll_items);
|
||||
RB_REMOVE(poll_items, &poll_items, pitem);
|
||||
xfree(pitem);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create server socket. */
|
||||
int
|
||||
@ -190,39 +107,14 @@ server_create_socket(void)
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/* Callback for server socket. */
|
||||
void
|
||||
server_callback(int fd, int events, unused void *data)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t slen = sizeof sa;
|
||||
int newfd;
|
||||
|
||||
if (events & (POLLERR|POLLNVAL|POLLHUP))
|
||||
fatalx("lost server socket");
|
||||
if (!(events & POLLIN))
|
||||
return;
|
||||
|
||||
newfd = accept(fd, (struct sockaddr *) &sa, &slen);
|
||||
if (newfd == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
|
||||
return;
|
||||
fatal("accept failed");
|
||||
}
|
||||
if (sigterm) {
|
||||
close(newfd);
|
||||
return;
|
||||
}
|
||||
server_client_create(newfd);
|
||||
}
|
||||
|
||||
/* Fork new server. */
|
||||
int
|
||||
server_start(char *path)
|
||||
{
|
||||
struct client *c;
|
||||
int pair[2], srv_fd;
|
||||
int pair[2];
|
||||
char *cause;
|
||||
struct timeval tv;
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
char rpathbuf[MAXPATHLEN];
|
||||
#endif
|
||||
@ -272,7 +164,7 @@ server_start(char *path)
|
||||
setproctitle("server (%s)", rpathbuf);
|
||||
#endif
|
||||
|
||||
srv_fd = server_create_socket();
|
||||
server_fd = server_create_socket();
|
||||
server_client_create(pair[1]);
|
||||
|
||||
if (access(SYSTEM_CFG, R_OK) == 0) {
|
||||
@ -285,7 +177,20 @@ server_start(char *path)
|
||||
if (cfg_file != NULL && load_cfg(cfg_file, NULL, &cause) != 0)
|
||||
goto error;
|
||||
|
||||
exit(server_main(srv_fd));
|
||||
event_init();
|
||||
|
||||
event_set(&server_ev_accept,
|
||||
server_fd, EV_READ|EV_PERSIST, server_accept_callback, NULL);
|
||||
event_add(&server_ev_accept, NULL);
|
||||
|
||||
memset(&tv, 0, sizeof tv);
|
||||
tv.tv_sec = 1;
|
||||
evtimer_set(&server_ev_second, server_second_callback, NULL);
|
||||
evtimer_add(&server_ev_second, &tv);
|
||||
|
||||
server_signal_set();
|
||||
server_loop();
|
||||
exit(0);
|
||||
|
||||
error:
|
||||
/* Write the error and shutdown the server. */
|
||||
@ -294,150 +199,39 @@ error:
|
||||
server_write_error(c, cause);
|
||||
xfree(cause);
|
||||
|
||||
sigterm = 1;
|
||||
server_shutdown();
|
||||
server_shutdown = 1;
|
||||
|
||||
exit(server_main(srv_fd));
|
||||
server_signal_set();
|
||||
server_loop();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Main server loop. */
|
||||
int
|
||||
server_main(int srv_fd)
|
||||
void
|
||||
server_loop(void)
|
||||
{
|
||||
struct pollfd *pfds;
|
||||
int nfds, xtimeout;
|
||||
u_int i;
|
||||
time_t now, last;
|
||||
struct timeval tv;
|
||||
|
||||
siginit();
|
||||
log_debug("server socket is %d", srv_fd);
|
||||
memset(&tv, 0, sizeof tv);
|
||||
tv.tv_usec = POLL_TIMEOUT * 1000;
|
||||
|
||||
last = time(NULL);
|
||||
while (!server_should_shutdown()) {
|
||||
server_update_socket();
|
||||
|
||||
pfds = NULL;
|
||||
for (;;) {
|
||||
/* If sigterm, kill all windows and clients. */
|
||||
if (sigterm)
|
||||
server_shutdown();
|
||||
|
||||
/* Stop if no sessions or clients left. */
|
||||
if (server_should_shutdown())
|
||||
break;
|
||||
|
||||
/* Handle child exit. */
|
||||
if (sigchld) {
|
||||
sigchld = 0;
|
||||
server_child_signal();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Recreate socket on SIGUSR1. */
|
||||
if (sigusr1) {
|
||||
sigusr1 = 0;
|
||||
close(srv_fd);
|
||||
srv_fd = server_create_socket();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Initialise pollfd array and add server socket. */
|
||||
server_poll_reset();
|
||||
server_poll_add(srv_fd, POLLIN, server_callback, NULL);
|
||||
|
||||
/* Fill window and client sockets. */
|
||||
server_job_prepare();
|
||||
server_window_prepare();
|
||||
server_client_prepare();
|
||||
|
||||
/* Update socket permissions. */
|
||||
xtimeout = INFTIM;
|
||||
if (server_update_socket() != 0)
|
||||
xtimeout = POLL_TIMEOUT;
|
||||
|
||||
/* Do the poll. */
|
||||
pfds = server_poll_flatten(&nfds);
|
||||
if (poll(pfds, nfds, xtimeout) == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
fatal("poll failed");
|
||||
}
|
||||
server_poll_dispatch(pfds, nfds);
|
||||
event_loopexit(&tv);
|
||||
event_loop(EVLOOP_ONCE);
|
||||
|
||||
/* Call second-based timers. */
|
||||
now = time(NULL);
|
||||
if (now != last) {
|
||||
last = now;
|
||||
server_second_timers();
|
||||
}
|
||||
|
||||
/* Run once-per-loop events. */
|
||||
server_job_loop();
|
||||
server_window_loop();
|
||||
server_client_loop();
|
||||
|
||||
/* Collect any unset key bindings. */
|
||||
key_bindings_clean();
|
||||
|
||||
/* Collect dead clients and sessions. */
|
||||
server_clean_dead();
|
||||
}
|
||||
server_poll_reset();
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if (ARRAY_ITEM(&sessions, i) != NULL)
|
||||
session_destroy(ARRAY_ITEM(&sessions, i));
|
||||
}
|
||||
ARRAY_FREE(&sessions);
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
if (ARRAY_ITEM(&clients, i) != NULL)
|
||||
server_client_lost(ARRAY_ITEM(&clients, i));
|
||||
}
|
||||
ARRAY_FREE(&clients);
|
||||
|
||||
mode_key_free_trees();
|
||||
key_bindings_free();
|
||||
|
||||
close(srv_fd);
|
||||
|
||||
unlink(socket_path);
|
||||
xfree(socket_path);
|
||||
|
||||
options_free(&global_s_options);
|
||||
options_free(&global_w_options);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Kill all clients. */
|
||||
void
|
||||
server_shutdown(void)
|
||||
{
|
||||
struct session *s;
|
||||
struct client *c;
|
||||
u_int i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c != NULL) {
|
||||
if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
|
||||
server_client_lost(c);
|
||||
else
|
||||
server_write_client(c, MSG_SHUTDOWN, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
for (j = 0; j < ARRAY_LENGTH(&clients); j++) {
|
||||
c = ARRAY_ITEM(&clients, j);
|
||||
if (c != NULL && c->session == s) {
|
||||
s = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s != NULL)
|
||||
session_destroy(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the server should be shutting down (no more clients or windows). */
|
||||
@ -457,49 +251,28 @@ server_should_shutdown(void)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Handle SIGCHLD. */
|
||||
/* Shutdown the server by killing all clients and windows. */
|
||||
void
|
||||
server_child_signal(void)
|
||||
server_send_shutdown(void)
|
||||
{
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct job *job;
|
||||
int status;
|
||||
pid_t pid;
|
||||
u_int i;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
u_int i;
|
||||
|
||||
for (;;) {
|
||||
switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
|
||||
case -1:
|
||||
if (errno == ECHILD)
|
||||
return;
|
||||
fatal("waitpid failed");
|
||||
case 0:
|
||||
return;
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c != NULL) {
|
||||
if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED))
|
||||
server_client_lost(c);
|
||||
else
|
||||
server_write_client(c, MSG_SHUTDOWN, NULL, 0);
|
||||
c->session = NULL;
|
||||
}
|
||||
if (!WIFSTOPPED(status)) {
|
||||
SLIST_FOREACH(job, &all_jobs, lentry) {
|
||||
if (pid == job->pid) {
|
||||
job->pid = -1;
|
||||
job->status = status;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
|
||||
w = ARRAY_ITEM(&windows, i);
|
||||
if (w == NULL)
|
||||
continue;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->pid == pid) {
|
||||
if (killpg(pid, SIGCONT) != 0)
|
||||
kill(pid, SIGCONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
if ((s = ARRAY_ITEM(&sessions, i)) != NULL)
|
||||
session_destroy(s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,12 +301,215 @@ server_clean_dead(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Call any once-per-second timers. */
|
||||
/* Update socket execute permissions based on whether sessions are attached. */
|
||||
int
|
||||
server_update_socket(void)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
static int last = -1;
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n != last) {
|
||||
last = n;
|
||||
if (n != 0)
|
||||
chmod(socket_path, S_IRWXU);
|
||||
else
|
||||
chmod(socket_path, S_IRUSR|S_IWUSR);
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
/* Callback for server socket. */
|
||||
void
|
||||
server_second_timers(void)
|
||||
server_accept_callback(int fd, short events, unused void *data)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t slen = sizeof sa;
|
||||
int newfd;
|
||||
|
||||
if (!(events & EV_READ))
|
||||
return;
|
||||
|
||||
newfd = accept(fd, (struct sockaddr *) &sa, &slen);
|
||||
if (newfd == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED)
|
||||
return;
|
||||
fatal("accept failed");
|
||||
}
|
||||
if (server_shutdown) {
|
||||
close(newfd);
|
||||
return;
|
||||
}
|
||||
server_client_create(newfd);
|
||||
|
||||
}
|
||||
|
||||
/* Set up server signal handling. */
|
||||
void
|
||||
server_signal_set(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&server_ev_sigchld, SIGCHLD, server_signal_callback, NULL);
|
||||
signal_add(&server_ev_sigchld, NULL);
|
||||
signal_set(&server_ev_sigterm, SIGTERM, server_signal_callback, NULL);
|
||||
signal_add(&server_ev_sigterm, NULL);
|
||||
signal_set(&server_ev_sigusr1, SIGUSR1, server_signal_callback, NULL);
|
||||
signal_add(&server_ev_sigusr1, NULL);
|
||||
}
|
||||
|
||||
/* Destroy server signal events. */
|
||||
void
|
||||
server_signal_clear(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_del(&server_ev_sigchld);
|
||||
signal_del(&server_ev_sigterm);
|
||||
signal_del(&server_ev_sigusr1);
|
||||
}
|
||||
|
||||
/* Signal handler. */
|
||||
void
|
||||
server_signal_callback(int sig, unused short events, unused void *data)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
server_shutdown = 1;
|
||||
server_send_shutdown();
|
||||
break;
|
||||
case SIGCHLD:
|
||||
server_child_signal();
|
||||
break;
|
||||
case SIGUSR1:
|
||||
event_del(&server_ev_accept);
|
||||
close(server_fd);
|
||||
server_fd = server_create_socket();
|
||||
event_set(&server_ev_accept, server_fd,
|
||||
EV_READ|EV_PERSIST, server_accept_callback, NULL);
|
||||
event_add(&server_ev_accept, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle SIGCHLD. */
|
||||
void
|
||||
server_child_signal(void)
|
||||
{
|
||||
int status;
|
||||
pid_t pid;
|
||||
|
||||
for (;;) {
|
||||
switch (pid = waitpid(WAIT_ANY, &status, WNOHANG|WUNTRACED)) {
|
||||
case -1:
|
||||
if (errno == ECHILD)
|
||||
return;
|
||||
fatal("waitpid failed");
|
||||
case 0:
|
||||
return;
|
||||
}
|
||||
if (WIFSTOPPED(status))
|
||||
server_child_stopped(pid, status);
|
||||
else if (WIFEXITED(status))
|
||||
server_child_exited(pid, status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle exited children. */
|
||||
void
|
||||
server_child_exited(pid_t pid, int status)
|
||||
{
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct job *job;
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
|
||||
if ((w = ARRAY_ITEM(&windows, i)) == NULL)
|
||||
continue;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->pid == pid) {
|
||||
close(wp->fd);
|
||||
wp->fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SLIST_FOREACH(job, &all_jobs, lentry) {
|
||||
if (pid == job->pid) {
|
||||
job->pid = -1;
|
||||
job->status = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle stopped children. */
|
||||
void
|
||||
server_child_stopped(pid_t pid, int status)
|
||||
{
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
u_int i;
|
||||
|
||||
if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
|
||||
if ((w = ARRAY_ITEM(&windows, i)) == NULL)
|
||||
continue;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->pid == pid) {
|
||||
if (killpg(pid, SIGCONT) != 0)
|
||||
kill(pid, SIGCONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle once-per-second timer events. */
|
||||
void
|
||||
server_second_callback(unused int fd, unused short events, unused void *arg)
|
||||
{
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct timeval tv;
|
||||
u_int i;
|
||||
|
||||
if (options_get_number(&global_s_options, "lock-server"))
|
||||
@ -551,6 +527,11 @@ server_second_timers(void)
|
||||
wp->mode->timer(wp);
|
||||
}
|
||||
}
|
||||
|
||||
evtimer_del(&server_ev_second);
|
||||
memset(&tv, 0, sizeof tv);
|
||||
tv.tv_sec = 1;
|
||||
evtimer_add(&server_ev_second, &tv);
|
||||
}
|
||||
|
||||
/* Lock the server if ALL sessions have hit the time limit. */
|
||||
@ -609,32 +590,3 @@ server_lock_sessions(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update socket execute permissions based on whether sessions are attached. */
|
||||
int
|
||||
server_update_socket(void)
|
||||
{
|
||||
struct session *s;
|
||||
u_int i;
|
||||
static int last = -1;
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < ARRAY_LENGTH(&sessions); i++) {
|
||||
s = ARRAY_ITEM(&sessions, i);
|
||||
if (s != NULL && !(s->flags & SESSION_UNATTACHED)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n != last) {
|
||||
last = n;
|
||||
if (n != 0)
|
||||
chmod(socket_path, S_IRWXU);
|
||||
else
|
||||
chmod(socket_path, S_IRUSR|S_IWUSR);
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
305
tmux.c
305
tmux.c
@ -1,4 +1,4 @@
|
||||
/* $Id: tmux.c,v 1.184 2009-11-04 23:09:09 tcunha Exp $ */
|
||||
/* $Id: tmux.c,v 1.185 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -20,6 +20,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
@ -33,13 +34,6 @@
|
||||
extern char *malloc_options;
|
||||
#endif
|
||||
|
||||
volatile sig_atomic_t sigwinch;
|
||||
volatile sig_atomic_t sigterm;
|
||||
volatile sig_atomic_t sigcont;
|
||||
volatile sig_atomic_t sigchld;
|
||||
volatile sig_atomic_t sigusr1;
|
||||
volatile sig_atomic_t sigusr2;
|
||||
|
||||
char *cfg_file;
|
||||
struct options global_s_options; /* session options */
|
||||
struct options global_w_options; /* window options */
|
||||
@ -54,9 +48,18 @@ int login_shell;
|
||||
__dead void usage(void);
|
||||
void fill_session(struct msg_command_data *);
|
||||
char *makesockpath(const char *);
|
||||
int dispatch_imsg(struct imsgbuf *, const char *, int *);
|
||||
__dead void shell_exec(const char *, const char *);
|
||||
|
||||
struct imsgbuf *main_ibuf;
|
||||
struct event main_ev_sigterm;
|
||||
int main_exitval;
|
||||
|
||||
void main_set_signals(void);
|
||||
void main_clear_signals(void);
|
||||
void main_signal(int, short, unused void *);
|
||||
void main_callback(int, short, void *);
|
||||
void main_dispatch(const char *);
|
||||
|
||||
#ifndef HAVE_PROGNAME
|
||||
char *__progname = (char *) "tmux";
|
||||
#endif
|
||||
@ -84,96 +87,6 @@ logfile(const char *name)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sighandler(int sig)
|
||||
{
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
switch (sig) {
|
||||
case SIGWINCH:
|
||||
sigwinch = 1;
|
||||
break;
|
||||
case SIGTERM:
|
||||
sigterm = 1;
|
||||
break;
|
||||
case SIGCHLD:
|
||||
sigchld = 1;
|
||||
break;
|
||||
case SIGCONT:
|
||||
sigcont = 1;
|
||||
break;
|
||||
case SIGUSR1:
|
||||
sigusr1 = 1;
|
||||
break;
|
||||
case SIGUSR2:
|
||||
sigusr2 = 1;
|
||||
break;
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
void
|
||||
siginit(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
memset(&act, 0, sizeof act);
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_RESTART;
|
||||
|
||||
act.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGPIPE, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGINT, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGQUIT, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
act.sa_handler = sighandler;
|
||||
if (sigaction(SIGWINCH, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTERM, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGCHLD, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
}
|
||||
|
||||
void
|
||||
sigreset(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
memset(&act, 0, sizeof act);
|
||||
sigemptyset(&act.sa_mask);
|
||||
|
||||
act.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGPIPE, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGINT, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGQUIT, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGWINCH, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTERM, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGCHLD, &act, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
}
|
||||
|
||||
const char *
|
||||
getshell(void)
|
||||
{
|
||||
@ -284,23 +197,43 @@ makesockpath(const char *label)
|
||||
return (path);
|
||||
}
|
||||
|
||||
__dead void
|
||||
shell_exec(const char *shell, const char *shellcmd)
|
||||
{
|
||||
const char *shellname, *ptr;
|
||||
char *argv0;
|
||||
|
||||
ptr = strrchr(shell, '/');
|
||||
if (ptr != NULL && *(ptr + 1) != '\0')
|
||||
shellname = ptr + 1;
|
||||
else
|
||||
shellname = shell;
|
||||
if (login_shell)
|
||||
xasprintf(&argv0, "-%s", shellname);
|
||||
else
|
||||
xasprintf(&argv0, "%s", shellname);
|
||||
setenv("SHELL", shell, 1);
|
||||
|
||||
execl(shell, argv0, "-c", shellcmd, (char *) NULL);
|
||||
fatal("execl failed");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
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;
|
||||
struct msg_command_data cmddata;
|
||||
char *s, *shellcmd, *path, *label, *home, *cause;
|
||||
char cwd[MAXPATHLEN], **var;
|
||||
void *buf;
|
||||
size_t len;
|
||||
int nfds, retcode, opt, flags, cmdflags = 0;
|
||||
int opt, flags, cmdflags = 0;
|
||||
short events;
|
||||
|
||||
#if defined(DEBUG) && defined(__OpenBSD__)
|
||||
malloc_options = (char *) "AFGJPX";
|
||||
@ -362,7 +295,6 @@ main(int argc, char **argv)
|
||||
usage();
|
||||
|
||||
log_open_tty(debug_level);
|
||||
siginit();
|
||||
|
||||
if (!(flags & IDENTIFY_UTF8)) {
|
||||
/*
|
||||
@ -552,63 +484,121 @@ main(int argc, char **argv)
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
if ((ibuf = client_init(path, cmdflags, flags)) == NULL)
|
||||
if ((main_ibuf = client_init(path, cmdflags, flags)) == NULL)
|
||||
exit(1);
|
||||
xfree(path);
|
||||
|
||||
imsg_compose(ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
|
||||
event_init();
|
||||
|
||||
retcode = 0;
|
||||
for (;;) {
|
||||
pfd.fd = ibuf->fd;
|
||||
pfd.events = POLLIN;
|
||||
if (ibuf->w.queued != 0)
|
||||
pfd.events |= POLLOUT;
|
||||
imsg_compose(main_ibuf, msg, PROTOCOL_VERSION, -1, -1, buf, len);
|
||||
|
||||
if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
fatal("poll failed");
|
||||
}
|
||||
if (nfds == 0)
|
||||
continue;
|
||||
main_set_signals();
|
||||
|
||||
if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
|
||||
fatalx("socket error");
|
||||
events = EV_READ;
|
||||
if (main_ibuf->w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
|
||||
|
||||
if (pfd.revents & POLLIN) {
|
||||
if (dispatch_imsg(ibuf, shellcmd, &retcode) != 0)
|
||||
break;
|
||||
}
|
||||
main_exitval = 0;
|
||||
event_dispatch();
|
||||
|
||||
if (pfd.revents & POLLOUT) {
|
||||
if (msgbuf_write(&ibuf->w) < 0)
|
||||
fatalx("msgbuf_write failed");
|
||||
}
|
||||
}
|
||||
main_clear_signals();
|
||||
|
||||
options_free(&global_s_options);
|
||||
options_free(&global_w_options);
|
||||
|
||||
return (retcode);
|
||||
client_main(); /* doesn't return */
|
||||
}
|
||||
|
||||
int
|
||||
dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
|
||||
|
||||
void
|
||||
main_set_signals(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
signal_set(&main_ev_sigterm, SIGTERM, main_signal, NULL);
|
||||
signal_add(&main_ev_sigterm, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
main_clear_signals(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof sigact);
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR1, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
|
||||
event_del(&main_ev_sigterm);
|
||||
}
|
||||
|
||||
void
|
||||
main_signal(int sig, unused short events, unused void *data)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
main_callback(unused int fd, short events, void *data)
|
||||
{
|
||||
char *shellcmd = data;
|
||||
|
||||
if (events & EV_READ)
|
||||
main_dispatch(shellcmd);
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
if (msgbuf_write(&main_ibuf->w) < 0)
|
||||
fatalx("msgbuf_write failed");
|
||||
}
|
||||
|
||||
events = EV_READ;
|
||||
if (main_ibuf->w.queued > 0)
|
||||
events |= EV_WRITE;
|
||||
event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
main_dispatch(const char *shellcmd)
|
||||
{
|
||||
struct imsg imsg;
|
||||
ssize_t n, datalen;
|
||||
struct msg_print_data printdata;
|
||||
struct msg_shell_data shelldata;
|
||||
|
||||
if ((n = imsg_read(ibuf)) == -1 || n == 0)
|
||||
if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
|
||||
fatalx("imsg_read failed");
|
||||
|
||||
for (;;) {
|
||||
if ((n = imsg_get(ibuf, &imsg)) == -1)
|
||||
if ((n = imsg_get(main_ibuf, &imsg)) == -1)
|
||||
fatalx("imsg_get failed");
|
||||
if (n == 0)
|
||||
return (0);
|
||||
return;
|
||||
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
|
||||
|
||||
switch (imsg.hdr.type) {
|
||||
@ -617,10 +607,8 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_EXIT size");
|
||||
|
||||
return (-1);
|
||||
exit(main_exitval);
|
||||
case MSG_ERROR:
|
||||
*retcode = 1;
|
||||
/* FALLTHROUGH */
|
||||
case MSG_PRINT:
|
||||
if (datalen != sizeof printdata)
|
||||
fatalx("bad MSG_PRINT size");
|
||||
@ -628,26 +616,30 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
|
||||
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
|
||||
|
||||
log_info("%s", printdata.msg);
|
||||
if (imsg.hdr.type == MSG_ERROR)
|
||||
main_exitval = 1;
|
||||
break;
|
||||
case MSG_READY:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_READY size");
|
||||
|
||||
client_main(); /* doesn't return */
|
||||
event_loopexit(NULL); /* move to client_main() */
|
||||
break;
|
||||
case MSG_VERSION:
|
||||
if (datalen != 0)
|
||||
fatalx("bad MSG_VERSION size");
|
||||
|
||||
log_warnx("protocol version mismatch (client %u, "
|
||||
"server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
|
||||
*retcode = 1;
|
||||
return (-1);
|
||||
exit(1);
|
||||
case MSG_SHELL:
|
||||
if (datalen != sizeof shelldata)
|
||||
fatalx("bad MSG_SHELL size");
|
||||
memcpy(&shelldata, imsg.data, sizeof shelldata);
|
||||
shelldata.shell[(sizeof shelldata.shell) - 1] = '\0';
|
||||
|
||||
|
||||
main_clear_signals();
|
||||
|
||||
shell_exec(shelldata.shell, shellcmd);
|
||||
default:
|
||||
fatalx("unexpected message");
|
||||
@ -656,26 +648,3 @@ dispatch_imsg(struct imsgbuf *ibuf, const char *shellcmd, int *retcode)
|
||||
imsg_free(&imsg);
|
||||
}
|
||||
}
|
||||
|
||||
__dead void
|
||||
shell_exec(const char *shell, const char *shellcmd)
|
||||
{
|
||||
const char *shellname, *ptr;
|
||||
char *argv0;
|
||||
|
||||
sigreset();
|
||||
|
||||
ptr = strrchr(shell, '/');
|
||||
if (ptr != NULL && *(ptr + 1) != '\0')
|
||||
shellname = ptr + 1;
|
||||
else
|
||||
shellname = shell;
|
||||
if (login_shell)
|
||||
xasprintf(&argv0, "-%s", shellname);
|
||||
else
|
||||
xasprintf(&argv0, "%s", shellname);
|
||||
setenv("SHELL", shell, 1);
|
||||
|
||||
execl(shell, argv0, "-c", shellcmd, (char *) NULL);
|
||||
fatal("execl failed");
|
||||
}
|
||||
|
29
tmux.h
29
tmux.h
@ -1,4 +1,4 @@
|
||||
/* $Id: tmux.h,v 1.496 2009-11-04 22:46:25 tcunha Exp $ */
|
||||
/* $Id: tmux.h,v 1.497 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -27,6 +27,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <event.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
@ -659,6 +660,7 @@ struct job {
|
||||
struct client *client;
|
||||
|
||||
int fd;
|
||||
struct event event;
|
||||
struct buffer *out;
|
||||
|
||||
void (*callbackfn)(struct job *);
|
||||
@ -794,14 +796,17 @@ struct window_pane {
|
||||
char *cwd;
|
||||
|
||||
pid_t pid;
|
||||
int fd;
|
||||
char tty[TTY_NAME_MAX];
|
||||
|
||||
int fd;
|
||||
struct event event;
|
||||
struct buffer *in;
|
||||
struct buffer *out;
|
||||
|
||||
struct input_ctx ictx;
|
||||
|
||||
int pipe_fd;
|
||||
struct event pipe_event;
|
||||
struct buffer *pipe_buf;
|
||||
size_t pipe_off;
|
||||
|
||||
@ -996,6 +1001,7 @@ struct tty {
|
||||
struct tty_term *term;
|
||||
|
||||
int fd;
|
||||
struct event event;
|
||||
struct buffer *in;
|
||||
struct buffer *out;
|
||||
|
||||
@ -1060,6 +1066,7 @@ struct mouse_event {
|
||||
/* Client connection. */
|
||||
struct client {
|
||||
struct imsgbuf ibuf;
|
||||
struct event event;
|
||||
|
||||
struct timeval creation_time;
|
||||
struct timeval activity_time;
|
||||
@ -1233,12 +1240,6 @@ extern const struct set_option_entry set_option_table[];
|
||||
extern const struct set_option_entry set_window_option_table[];
|
||||
|
||||
/* tmux.c */
|
||||
extern volatile sig_atomic_t sigwinch;
|
||||
extern volatile sig_atomic_t sigterm;
|
||||
extern volatile sig_atomic_t sigcont;
|
||||
extern volatile sig_atomic_t sigchld;
|
||||
extern volatile sig_atomic_t sigusr1;
|
||||
extern volatile sig_atomic_t sigusr2;
|
||||
extern struct options global_s_options;
|
||||
extern struct options global_w_options;
|
||||
extern struct environ global_environ;
|
||||
@ -1249,9 +1250,6 @@ extern time_t start_time;
|
||||
extern char *socket_path;
|
||||
extern int login_shell;
|
||||
void logfile(const char *);
|
||||
void siginit(void);
|
||||
void sigreset(void);
|
||||
void sighandler(int);
|
||||
const char *getshell(void);
|
||||
int checkshell(const char *);
|
||||
int areshell(const char *);
|
||||
@ -1580,23 +1578,24 @@ const char *key_string_lookup_key(int);
|
||||
extern struct clients clients;
|
||||
extern struct clients dead_clients;
|
||||
int server_start(char *);
|
||||
void server_poll_add(int, int, void (*)(int, int, void *), void *);
|
||||
void server_signal_set(void);
|
||||
void server_signal_clear(void);
|
||||
|
||||
/* server-client.c */
|
||||
void server_client_create(int);
|
||||
void server_client_lost(struct client *);
|
||||
void server_client_prepare(void);
|
||||
void server_client_callback(int, int, void *);
|
||||
void server_client_callback(int, short, void *);
|
||||
void server_client_loop(void);
|
||||
|
||||
/* server-job.c */
|
||||
void server_job_prepare(void);
|
||||
void server_job_callback(int, int, void *);
|
||||
void server_job_callback(int, short, void *);
|
||||
void server_job_loop(void);
|
||||
|
||||
/* server-window.c */
|
||||
void server_window_prepare(void);
|
||||
void server_window_callback(int, int, void *);
|
||||
void server_window_callback(int, short, void *);
|
||||
void server_window_loop(void);
|
||||
|
||||
/* server-fn.c */
|
||||
|
6
window.c
6
window.c
@ -1,4 +1,4 @@
|
||||
/* $Id: window.c,v 1.117 2009-10-23 17:41:20 tcunha Exp $ */
|
||||
/* $Id: window.c,v 1.118 2009-11-08 22:40:36 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -453,10 +453,12 @@ window_pane_destroy(struct window_pane *wp)
|
||||
if (wp->pipe_fd != -1) {
|
||||
buffer_destroy(wp->pipe_buf);
|
||||
close(wp->pipe_fd);
|
||||
event_del(&wp->pipe_event);
|
||||
}
|
||||
|
||||
buffer_destroy(wp->in);
|
||||
buffer_destroy(wp->out);
|
||||
event_del(&wp->event);
|
||||
|
||||
if (wp->cwd != NULL)
|
||||
xfree(wp->cwd);
|
||||
@ -541,7 +543,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||
setenv(envent->name, envent->value, 1);
|
||||
}
|
||||
|
||||
sigreset();
|
||||
server_signal_clear();
|
||||
log_close();
|
||||
|
||||
if (*wp->cmd != '\0') {
|
||||
|
Loading…
Reference in New Issue
Block a user