mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:26:05 +00:00 
			
		
		
		
	Switch tmux to use imsg. This is the last major change to make the
client-server protocol more resilient and make the protocol versioning work properly. In future, the only things requiring a protocol version bump will be changes in the message structs, and (when both client and server have this change) mixing different versions should nicely report an error message. As a side effect this also makes the code tidier, fixes a problem with the way errors reported during server startup were handled, and supports fd passing (which will be used in future). Looked over by eric@, thanks. Please note that mixing a client with this change with an older server or vice versa may cause tmux to crash or hang - tmux should be completely exited before upgrading.
This commit is contained in:
		
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							@@ -28,7 +28,8 @@ SRCS=	attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
 | 
			
		||||
	cmd-set-environment.c cmd-show-environment.c \
 | 
			
		||||
	cmd-up-pane.c cmd-display-message.c cmd.c \
 | 
			
		||||
	colour.c environ.c grid-view.c grid.c input-keys.c \
 | 
			
		||||
	input.c key-bindings.c key-string.c layout-set.c layout.c log.c \
 | 
			
		||||
	imsg.c imsg-buffer.c input.c key-bindings.c key-string.c \
 | 
			
		||||
	layout-set.c layout.c log.c \
 | 
			
		||||
	mode-key.c names.c options-cmd.c options.c paste.c procname.c \
 | 
			
		||||
	resize.c screen-redraw.c screen-write.c screen.c server-fn.c \
 | 
			
		||||
	server-msg.c server.c session.c status.c tmux.c tty-keys.c tty-term.c \
 | 
			
		||||
 
 | 
			
		||||
@@ -66,14 +66,7 @@ void
 | 
			
		||||
client_write_server(
 | 
			
		||||
    struct client_ctx *cctx, enum msgtype type, void *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct hdr	hdr;
 | 
			
		||||
 | 
			
		||||
	hdr.type = type;
 | 
			
		||||
	hdr.size = len;
 | 
			
		||||
	buffer_write(cctx->srv_out, &hdr, sizeof hdr);
 | 
			
		||||
 | 
			
		||||
	if (buf != NULL && len > 0)
 | 
			
		||||
		buffer_write(cctx->srv_out, buf, len);
 | 
			
		||||
	imsg_compose(&cctx->ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										70
									
								
								client.c
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								client.c
									
									
									
									
									
								
							@@ -92,16 +92,13 @@ server_started:
 | 
			
		||||
		fatal("fcntl failed");
 | 
			
		||||
	if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
 | 
			
		||||
		fatal("fcntl failed");
 | 
			
		||||
	cctx->srv_fd = fd;
 | 
			
		||||
	cctx->srv_in = buffer_create(BUFSIZ);
 | 
			
		||||
	cctx->srv_out = buffer_create(BUFSIZ);
 | 
			
		||||
	imsg_init(&cctx->ibuf, fd);
 | 
			
		||||
 | 
			
		||||
	if (cmdflags & CMD_SENDENVIRON)
 | 
			
		||||
		client_send_environ(cctx);
 | 
			
		||||
	if (isatty(STDIN_FILENO)) {
 | 
			
		||||
		if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
 | 
			
		||||
			fatal("ioctl(TIOCGWINSZ)");
 | 
			
		||||
		data.version = PROTOCOL_VERSION;
 | 
			
		||||
		data.flags = flags;
 | 
			
		||||
		data.sx = ws.ws_col;
 | 
			
		||||
		data.sy = ws.ws_row;
 | 
			
		||||
@@ -153,6 +150,7 @@ int
 | 
			
		||||
client_main(struct client_ctx *cctx)
 | 
			
		||||
{
 | 
			
		||||
	struct pollfd	 pfd;
 | 
			
		||||
	int		 nfds;
 | 
			
		||||
 | 
			
		||||
	siginit();
 | 
			
		||||
 | 
			
		||||
@@ -173,24 +171,33 @@ client_main(struct client_ctx *cctx)
 | 
			
		||||
			sigcont = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pfd.fd = cctx->srv_fd;
 | 
			
		||||
		pfd.fd = cctx->ibuf.fd;
 | 
			
		||||
		pfd.events = POLLIN;
 | 
			
		||||
		if (BUFFER_USED(cctx->srv_out) > 0)
 | 
			
		||||
		if (cctx->ibuf.w.queued > 0)
 | 
			
		||||
			pfd.events |= POLLOUT;
 | 
			
		||||
 | 
			
		||||
		if (poll(&pfd, 1, INFTIM) == -1) {
 | 
			
		||||
		if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
 | 
			
		||||
			if (errno == EAGAIN || errno == EINTR)
 | 
			
		||||
				continue;
 | 
			
		||||
			fatal("poll failed");
 | 
			
		||||
		}
 | 
			
		||||
		if (nfds == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) {
 | 
			
		||||
			cctx->exittype = CCTX_DIED;
 | 
			
		||||
			break;
 | 
			
		||||
		if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
 | 
			
		||||
			fatalx("socket error");
 | 
			
		||||
 | 
			
		||||
		if (pfd.revents & POLLIN) {
 | 
			
		||||
			if (client_msg_dispatch(cctx) != 0)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (client_msg_dispatch(cctx) != 0)
 | 
			
		||||
			break;
 | 
			
		||||
		if (pfd.revents & POLLOUT) {
 | 
			
		||||
			if (msgbuf_write(&cctx->ibuf.w) < 0) {
 | 
			
		||||
				cctx->exittype = CCTX_DIED;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 	if (sigterm) {
 | 
			
		||||
@@ -235,54 +242,61 @@ client_handle_winch(struct client_ctx *cctx)
 | 
			
		||||
int
 | 
			
		||||
client_msg_dispatch(struct client_ctx *cctx)
 | 
			
		||||
{
 | 
			
		||||
	struct hdr		 hdr;
 | 
			
		||||
	struct imsg		 imsg;
 | 
			
		||||
	struct msg_print_data	 printdata;
 | 
			
		||||
	ssize_t			 n, datalen;
 | 
			
		||||
 | 
			
		||||
	if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) {
 | 
			
		||||
		cctx->exittype = CCTX_DIED;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		if (BUFFER_USED(cctx->srv_in) < sizeof hdr)
 | 
			
		||||
		if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
 | 
			
		||||
			fatalx("imsg_get failed");
 | 
			
		||||
		if (n == 0)
 | 
			
		||||
			return (0);
 | 
			
		||||
		memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
 | 
			
		||||
		if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
 | 
			
		||||
			return (0);
 | 
			
		||||
		buffer_remove(cctx->srv_in, sizeof hdr);
 | 
			
		||||
		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
 | 
			
		||||
		switch (hdr.type) {
 | 
			
		||||
		switch (imsg.hdr.type) {
 | 
			
		||||
		case MSG_DETACH:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_DETACH size");
 | 
			
		||||
 | 
			
		||||
			client_write_server(cctx, MSG_EXITING, NULL, 0);
 | 
			
		||||
			cctx->exittype = CCTX_DETACH;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_ERROR:
 | 
			
		||||
			if (hdr.size != sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_PRINT size");
 | 
			
		||||
			buffer_read(cctx->srv_in, &printdata, sizeof printdata);
 | 
			
		||||
			if (datalen != sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_ERROR size");
 | 
			
		||||
			memcpy(&printdata, imsg.data, sizeof printdata);
 | 
			
		||||
 | 
			
		||||
			printdata.msg[(sizeof printdata.msg) - 1] = '\0';
 | 
			
		||||
			cctx->errstr = xstrdup(printdata.msg);
 | 
			
		||||
			imsg_free(&imsg);
 | 
			
		||||
			return (-1);
 | 
			
		||||
		case MSG_EXIT:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_EXIT size");
 | 
			
		||||
 | 
			
		||||
			client_write_server(cctx, MSG_EXITING, NULL, 0);
 | 
			
		||||
			cctx->exittype = CCTX_EXIT;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_EXITED:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_EXITED size");
 | 
			
		||||
 | 
			
		||||
			imsg_free(&imsg);
 | 
			
		||||
			return (-1);
 | 
			
		||||
		case MSG_SHUTDOWN:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_SHUTDOWN size");
 | 
			
		||||
 | 
			
		||||
			client_write_server(cctx, MSG_EXITING, NULL, 0);
 | 
			
		||||
			cctx->exittype = CCTX_SHUTDOWN;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_SUSPEND:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_SUSPEND size");
 | 
			
		||||
 | 
			
		||||
			client_suspend();
 | 
			
		||||
@@ -290,5 +304,7 @@ client_msg_dispatch(struct client_ctx *cctx)
 | 
			
		||||
		default:
 | 
			
		||||
			fatalx("unexpected message");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		imsg_free(&imsg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ cmd_server_info_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		ctx->print(ctx, "%2d: %s (%d, %d): %s [%ux%u %s] "
 | 
			
		||||
		    "[flags=0x%x/0x%x]", i, c->tty.path, c->fd, c->tty.fd,
 | 
			
		||||
		    "[flags=0x%x/0x%x]", i, c->tty.path, c->ibuf.fd, c->tty.fd,
 | 
			
		||||
		    c->session->name, c->tty.sx, c->tty.sy, c->tty.termname,
 | 
			
		||||
		    c->flags, c->tty.flags);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										305
									
								
								imsg-buffer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								imsg-buffer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,305 @@
 | 
			
		||||
/*	$OpenBSD$	*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
 | 
			
		||||
 *
 | 
			
		||||
 * 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 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/param.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/uio.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "imsg.h"
 | 
			
		||||
 | 
			
		||||
int	buf_realloc(struct buf *, size_t);
 | 
			
		||||
void	buf_enqueue(struct msgbuf *, struct buf *);
 | 
			
		||||
void	buf_dequeue(struct msgbuf *, struct buf *);
 | 
			
		||||
 | 
			
		||||
struct buf *
 | 
			
		||||
buf_open(size_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct buf	*buf;
 | 
			
		||||
 | 
			
		||||
	if ((buf = calloc(1, sizeof(struct buf))) == NULL)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	if ((buf->buf = malloc(len)) == NULL) {
 | 
			
		||||
		free(buf);
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	}
 | 
			
		||||
	buf->size = buf->max = len;
 | 
			
		||||
	buf->fd = -1;
 | 
			
		||||
 | 
			
		||||
	return (buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct buf *
 | 
			
		||||
buf_dynamic(size_t len, size_t max)
 | 
			
		||||
{
 | 
			
		||||
	struct buf	*buf;
 | 
			
		||||
 | 
			
		||||
	if (max < len)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	if ((buf = buf_open(len)) == NULL)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	if (max > 0)
 | 
			
		||||
		buf->max = max;
 | 
			
		||||
 | 
			
		||||
	return (buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
buf_realloc(struct buf *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	u_char	*b;
 | 
			
		||||
 | 
			
		||||
	/* on static buffers max is eq size and so the following fails */
 | 
			
		||||
	if (buf->wpos + len > buf->max) {
 | 
			
		||||
		errno = ENOMEM;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b = realloc(buf->buf, buf->wpos + len);
 | 
			
		||||
	if (b == NULL)
 | 
			
		||||
		return (-1);
 | 
			
		||||
	buf->buf = b;
 | 
			
		||||
	buf->size = buf->wpos + len;
 | 
			
		||||
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
buf_add(struct buf *buf, const void *data, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (buf->wpos + len > buf->size)
 | 
			
		||||
		if (buf_realloc(buf, len) == -1)
 | 
			
		||||
			return (-1);
 | 
			
		||||
 | 
			
		||||
	memcpy(buf->buf + buf->wpos, data, len);
 | 
			
		||||
	buf->wpos += len;
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *
 | 
			
		||||
buf_reserve(struct buf *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	void	*b;
 | 
			
		||||
 | 
			
		||||
	if (buf->wpos + len > buf->size)
 | 
			
		||||
		if (buf_realloc(buf, len) == -1)
 | 
			
		||||
			return (NULL);
 | 
			
		||||
 | 
			
		||||
	b = buf->buf + buf->wpos;
 | 
			
		||||
	buf->wpos += len;
 | 
			
		||||
	return (b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *
 | 
			
		||||
buf_seek(struct buf *buf, size_t pos, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	/* only allowed to seek in already written parts */
 | 
			
		||||
	if (pos + len > buf->wpos)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	return (buf->buf + pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t
 | 
			
		||||
buf_size(struct buf *buf)
 | 
			
		||||
{
 | 
			
		||||
	return (buf->wpos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t
 | 
			
		||||
buf_left(struct buf *buf)
 | 
			
		||||
{
 | 
			
		||||
	return (buf->max - buf->wpos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
buf_close(struct msgbuf *msgbuf, struct buf *buf)
 | 
			
		||||
{
 | 
			
		||||
	buf_enqueue(msgbuf, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
buf_write(struct msgbuf *msgbuf)
 | 
			
		||||
{
 | 
			
		||||
	struct iovec	 iov[IOV_MAX];
 | 
			
		||||
	struct buf	*buf, *next;
 | 
			
		||||
	unsigned int	 i = 0;
 | 
			
		||||
	ssize_t	n;
 | 
			
		||||
 | 
			
		||||
	bzero(&iov, sizeof(iov));
 | 
			
		||||
	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
 | 
			
		||||
		if (i >= IOV_MAX)
 | 
			
		||||
			break;
 | 
			
		||||
		iov[i].iov_base = buf->buf + buf->rpos;
 | 
			
		||||
		iov[i].iov_len = buf->wpos - buf->rpos;
 | 
			
		||||
		i++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((n = writev(msgbuf->fd, iov, i)) == -1) {
 | 
			
		||||
		if (errno == EAGAIN || errno == ENOBUFS ||
 | 
			
		||||
		    errno == EINTR)	/* try later */
 | 
			
		||||
			return (0);
 | 
			
		||||
		else
 | 
			
		||||
			return (-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (n == 0) {			/* connection closed */
 | 
			
		||||
		errno = 0;
 | 
			
		||||
		return (-2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
 | 
			
		||||
	    buf = next) {
 | 
			
		||||
		next = TAILQ_NEXT(buf, entry);
 | 
			
		||||
		if (buf->rpos + n >= buf->wpos) {
 | 
			
		||||
			n -= buf->wpos - buf->rpos;
 | 
			
		||||
			buf_dequeue(msgbuf, buf);
 | 
			
		||||
		} else {
 | 
			
		||||
			buf->rpos += n;
 | 
			
		||||
			n = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
buf_free(struct buf *buf)
 | 
			
		||||
{
 | 
			
		||||
	free(buf->buf);
 | 
			
		||||
	free(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
msgbuf_init(struct msgbuf *msgbuf)
 | 
			
		||||
{
 | 
			
		||||
	msgbuf->queued = 0;
 | 
			
		||||
	msgbuf->fd = -1;
 | 
			
		||||
	TAILQ_INIT(&msgbuf->bufs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
msgbuf_clear(struct msgbuf *msgbuf)
 | 
			
		||||
{
 | 
			
		||||
	struct buf	*buf;
 | 
			
		||||
 | 
			
		||||
	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
 | 
			
		||||
		buf_dequeue(msgbuf, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
msgbuf_write(struct msgbuf *msgbuf)
 | 
			
		||||
{
 | 
			
		||||
	struct iovec	 iov[IOV_MAX];
 | 
			
		||||
	struct buf	*buf, *next;
 | 
			
		||||
	unsigned int	 i = 0;
 | 
			
		||||
	ssize_t		 n;
 | 
			
		||||
	struct msghdr	 msg;
 | 
			
		||||
	struct cmsghdr	*cmsg;
 | 
			
		||||
	union {
 | 
			
		||||
		struct cmsghdr	hdr;
 | 
			
		||||
		char		buf[CMSG_SPACE(sizeof(int))];
 | 
			
		||||
	} cmsgbuf;
 | 
			
		||||
 | 
			
		||||
	bzero(&iov, sizeof(iov));
 | 
			
		||||
	bzero(&msg, sizeof(msg));
 | 
			
		||||
	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
 | 
			
		||||
		if (i >= IOV_MAX)
 | 
			
		||||
			break;
 | 
			
		||||
		iov[i].iov_base = buf->buf + buf->rpos;
 | 
			
		||||
		iov[i].iov_len = buf->wpos - buf->rpos;
 | 
			
		||||
		i++;
 | 
			
		||||
		if (buf->fd != -1)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg.msg_iov = iov;
 | 
			
		||||
	msg.msg_iovlen = i;
 | 
			
		||||
 | 
			
		||||
	if (buf != NULL && buf->fd != -1) {
 | 
			
		||||
		msg.msg_control = (caddr_t)&cmsgbuf.buf;
 | 
			
		||||
		msg.msg_controllen = sizeof(cmsgbuf.buf);
 | 
			
		||||
		cmsg = CMSG_FIRSTHDR(&msg);
 | 
			
		||||
		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
 | 
			
		||||
		cmsg->cmsg_level = SOL_SOCKET;
 | 
			
		||||
		cmsg->cmsg_type = SCM_RIGHTS;
 | 
			
		||||
		*(int *)CMSG_DATA(cmsg) = buf->fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
 | 
			
		||||
		if (errno == EAGAIN || errno == ENOBUFS ||
 | 
			
		||||
		    errno == EINTR)	/* try later */
 | 
			
		||||
			return (0);
 | 
			
		||||
		else
 | 
			
		||||
			return (-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (n == 0) {			/* connection closed */
 | 
			
		||||
		errno = 0;
 | 
			
		||||
		return (-2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * assumption: fd got sent if sendmsg sent anything
 | 
			
		||||
	 * this works because fds are passed one at a time
 | 
			
		||||
	 */
 | 
			
		||||
	if (buf != NULL && buf->fd != -1) {
 | 
			
		||||
		close(buf->fd);
 | 
			
		||||
		buf->fd = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
 | 
			
		||||
	    buf = next) {
 | 
			
		||||
		next = TAILQ_NEXT(buf, entry);
 | 
			
		||||
		if (buf->rpos + n >= buf->wpos) {
 | 
			
		||||
			n -= buf->wpos - buf->rpos;
 | 
			
		||||
			buf_dequeue(msgbuf, buf);
 | 
			
		||||
		} else {
 | 
			
		||||
			buf->rpos += n;
 | 
			
		||||
			n = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
buf_enqueue(struct msgbuf *msgbuf, struct buf *buf)
 | 
			
		||||
{
 | 
			
		||||
	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
 | 
			
		||||
	msgbuf->queued++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
buf_dequeue(struct msgbuf *msgbuf, struct buf *buf)
 | 
			
		||||
{
 | 
			
		||||
	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
 | 
			
		||||
 | 
			
		||||
	if (buf->fd != -1)
 | 
			
		||||
		close(buf->fd);
 | 
			
		||||
 | 
			
		||||
	msgbuf->queued--;
 | 
			
		||||
	buf_free(buf);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										271
									
								
								imsg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								imsg.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,271 @@
 | 
			
		||||
/*	$OpenBSD$	*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
 | 
			
		||||
 *
 | 
			
		||||
 * 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 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/param.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/uio.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "imsg.h"
 | 
			
		||||
 | 
			
		||||
int	 imsg_get_fd(struct imsgbuf *);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
imsg_init(struct imsgbuf *ibuf, int fd)
 | 
			
		||||
{
 | 
			
		||||
	msgbuf_init(&ibuf->w);
 | 
			
		||||
	bzero(&ibuf->r, sizeof(ibuf->r));
 | 
			
		||||
	ibuf->fd = fd;
 | 
			
		||||
	ibuf->w.fd = fd;
 | 
			
		||||
	ibuf->pid = getpid();
 | 
			
		||||
	TAILQ_INIT(&ibuf->fds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t
 | 
			
		||||
imsg_read(struct imsgbuf *ibuf)
 | 
			
		||||
{
 | 
			
		||||
	struct msghdr		 msg;
 | 
			
		||||
	struct cmsghdr		*cmsg;
 | 
			
		||||
	union {
 | 
			
		||||
		struct cmsghdr hdr;
 | 
			
		||||
		char	buf[CMSG_SPACE(sizeof(int) * 16)];
 | 
			
		||||
	} cmsgbuf;
 | 
			
		||||
	struct iovec		 iov;
 | 
			
		||||
	ssize_t			 n;
 | 
			
		||||
	int			 fd;
 | 
			
		||||
	struct imsg_fd		*ifd;
 | 
			
		||||
 | 
			
		||||
	bzero(&msg, sizeof(msg));
 | 
			
		||||
 | 
			
		||||
	iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
 | 
			
		||||
	iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
 | 
			
		||||
	msg.msg_iov = &iov;
 | 
			
		||||
	msg.msg_iovlen = 1;
 | 
			
		||||
	msg.msg_control = &cmsgbuf.buf;
 | 
			
		||||
	msg.msg_controllen = sizeof(cmsgbuf.buf);
 | 
			
		||||
 | 
			
		||||
	if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
 | 
			
		||||
		if (errno != EINTR && errno != EAGAIN) {
 | 
			
		||||
			return (-1);
 | 
			
		||||
		}
 | 
			
		||||
		return (-2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ibuf->r.wpos += n;
 | 
			
		||||
 | 
			
		||||
	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
 | 
			
		||||
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
 | 
			
		||||
		if (cmsg->cmsg_level == SOL_SOCKET &&
 | 
			
		||||
		    cmsg->cmsg_type == SCM_RIGHTS) {
 | 
			
		||||
			fd = (*(int *)CMSG_DATA(cmsg));
 | 
			
		||||
			if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) {
 | 
			
		||||
				/* XXX: this return can leak */
 | 
			
		||||
				return (-1);
 | 
			
		||||
			}
 | 
			
		||||
			ifd->fd = fd;
 | 
			
		||||
			TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry);
 | 
			
		||||
		}
 | 
			
		||||
		/* we do not handle other ctl data level */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t
 | 
			
		||||
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
 | 
			
		||||
{
 | 
			
		||||
	size_t			 av, left, datalen;
 | 
			
		||||
 | 
			
		||||
	av = ibuf->r.wpos;
 | 
			
		||||
 | 
			
		||||
	if (IMSG_HEADER_SIZE > av)
 | 
			
		||||
		return (0);
 | 
			
		||||
 | 
			
		||||
	memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
 | 
			
		||||
	if (imsg->hdr.len < IMSG_HEADER_SIZE ||
 | 
			
		||||
	    imsg->hdr.len > MAX_IMSGSIZE) {
 | 
			
		||||
		errno = ERANGE;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
	if (imsg->hdr.len > av)
 | 
			
		||||
		return (0);
 | 
			
		||||
	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
	ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
 | 
			
		||||
	if ((imsg->data = malloc(datalen)) == NULL)
 | 
			
		||||
		return (-1);
 | 
			
		||||
 | 
			
		||||
	if (imsg->hdr.flags & IMSGF_HASFD)
 | 
			
		||||
		imsg->fd = imsg_get_fd(ibuf);
 | 
			
		||||
	else
 | 
			
		||||
		imsg->fd = -1;
 | 
			
		||||
 | 
			
		||||
	memcpy(imsg->data, ibuf->r.rptr, datalen);
 | 
			
		||||
 | 
			
		||||
	if (imsg->hdr.len < av) {
 | 
			
		||||
		left = av - imsg->hdr.len;
 | 
			
		||||
		memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
 | 
			
		||||
		ibuf->r.wpos = left;
 | 
			
		||||
	} else
 | 
			
		||||
		ibuf->r.wpos = 0;
 | 
			
		||||
 | 
			
		||||
	return (datalen + IMSG_HEADER_SIZE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
 | 
			
		||||
    pid_t pid, int fd, void *data, u_int16_t datalen)
 | 
			
		||||
{
 | 
			
		||||
	struct buf	*wbuf;
 | 
			
		||||
 | 
			
		||||
	if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
 | 
			
		||||
		return (-1);
 | 
			
		||||
 | 
			
		||||
	if (imsg_add(wbuf, data, datalen) == -1)
 | 
			
		||||
		return (-1);
 | 
			
		||||
 | 
			
		||||
	wbuf->fd = fd;
 | 
			
		||||
 | 
			
		||||
	imsg_close(ibuf, wbuf);
 | 
			
		||||
 | 
			
		||||
	return (1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
 | 
			
		||||
    pid_t pid, int fd, const struct iovec *iov, int iovcnt)
 | 
			
		||||
{
 | 
			
		||||
	struct buf	*wbuf;
 | 
			
		||||
	int		 i, datalen = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < iovcnt; i++)
 | 
			
		||||
		datalen += iov[i].iov_len;
 | 
			
		||||
 | 
			
		||||
	if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
 | 
			
		||||
		return (-1);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < iovcnt; i++)
 | 
			
		||||
		if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
 | 
			
		||||
			return (-1);
 | 
			
		||||
 | 
			
		||||
	wbuf->fd = fd;
 | 
			
		||||
 | 
			
		||||
	imsg_close(ibuf, wbuf);
 | 
			
		||||
 | 
			
		||||
	return (1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ARGSUSED */
 | 
			
		||||
struct buf *
 | 
			
		||||
imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
 | 
			
		||||
    pid_t pid, u_int16_t datalen)
 | 
			
		||||
{
 | 
			
		||||
	struct buf	*wbuf;
 | 
			
		||||
	struct imsg_hdr	 hdr;
 | 
			
		||||
 | 
			
		||||
	datalen += IMSG_HEADER_SIZE;
 | 
			
		||||
	if (datalen > MAX_IMSGSIZE) {
 | 
			
		||||
		errno = ERANGE;
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hdr.type = type;
 | 
			
		||||
	hdr.flags = 0;
 | 
			
		||||
	hdr.peerid = peerid;
 | 
			
		||||
	if ((hdr.pid = pid) == 0)
 | 
			
		||||
		hdr.pid = ibuf->pid;
 | 
			
		||||
	if ((wbuf = buf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
 | 
			
		||||
		return (NULL);
 | 
			
		||||
	}
 | 
			
		||||
	if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	return (wbuf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
imsg_add(struct buf *msg, void *data, u_int16_t datalen)
 | 
			
		||||
{
 | 
			
		||||
	if (datalen)
 | 
			
		||||
		if (buf_add(msg, data, datalen) == -1) {
 | 
			
		||||
			buf_free(msg);
 | 
			
		||||
			return (-1);
 | 
			
		||||
		}
 | 
			
		||||
	return (datalen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
imsg_close(struct imsgbuf *ibuf, struct buf *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct imsg_hdr	*hdr;
 | 
			
		||||
 | 
			
		||||
	hdr = (struct imsg_hdr *)msg->buf;
 | 
			
		||||
 | 
			
		||||
	hdr->flags &= ~IMSGF_HASFD;
 | 
			
		||||
	if (msg->fd != -1)
 | 
			
		||||
		hdr->flags |= IMSGF_HASFD;
 | 
			
		||||
 | 
			
		||||
	hdr->len = (u_int16_t)msg->wpos;
 | 
			
		||||
 | 
			
		||||
	buf_close(&ibuf->w, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
imsg_free(struct imsg *imsg)
 | 
			
		||||
{
 | 
			
		||||
	free(imsg->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
imsg_get_fd(struct imsgbuf *ibuf)
 | 
			
		||||
{
 | 
			
		||||
	int		 fd;
 | 
			
		||||
	struct imsg_fd	*ifd;
 | 
			
		||||
 | 
			
		||||
	if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
 | 
			
		||||
		return (-1);
 | 
			
		||||
 | 
			
		||||
	fd = ifd->fd;
 | 
			
		||||
	TAILQ_REMOVE(&ibuf->fds, ifd, entry);
 | 
			
		||||
	free(ifd);
 | 
			
		||||
 | 
			
		||||
	return (fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
imsg_flush(struct imsgbuf *ibuf)
 | 
			
		||||
{
 | 
			
		||||
	while (ibuf->w.queued)
 | 
			
		||||
		if (msgbuf_write(&ibuf->w) < 0)
 | 
			
		||||
			return (-1);
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
imsg_clear(struct imsgbuf *ibuf)
 | 
			
		||||
{
 | 
			
		||||
	int	fd;
 | 
			
		||||
 | 
			
		||||
	msgbuf_clear(&ibuf->w);
 | 
			
		||||
	while ((fd = imsg_get_fd(ibuf)) != -1)
 | 
			
		||||
		close(fd);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								imsg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								imsg.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
/*	$OpenBSD$	*/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
 | 
			
		||||
 * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
 | 
			
		||||
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
 | 
			
		||||
 *
 | 
			
		||||
 * 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 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/tree.h>
 | 
			
		||||
 | 
			
		||||
#define READ_BUF_SIZE		65535
 | 
			
		||||
#define IMSG_HEADER_SIZE	sizeof(struct imsg_hdr)
 | 
			
		||||
#define MAX_IMSGSIZE		16384
 | 
			
		||||
 | 
			
		||||
struct buf {
 | 
			
		||||
	TAILQ_ENTRY(buf)	 entry;
 | 
			
		||||
	u_char			*buf;
 | 
			
		||||
	size_t			 size;
 | 
			
		||||
	size_t			 max;
 | 
			
		||||
	size_t			 wpos;
 | 
			
		||||
	size_t			 rpos;
 | 
			
		||||
	int			 fd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct msgbuf {
 | 
			
		||||
	TAILQ_HEAD(, buf)	 bufs;
 | 
			
		||||
	u_int32_t		 queued;
 | 
			
		||||
	int			 fd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct buf_read {
 | 
			
		||||
	u_char			 buf[READ_BUF_SIZE];
 | 
			
		||||
	u_char			*rptr;
 | 
			
		||||
	size_t			 wpos;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imsg_fd {
 | 
			
		||||
	TAILQ_ENTRY(imsg_fd)	entry;
 | 
			
		||||
	int			fd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imsgbuf {
 | 
			
		||||
	TAILQ_HEAD(, imsg_fd)	 fds;
 | 
			
		||||
	struct buf_read		 r;
 | 
			
		||||
	struct msgbuf		 w;
 | 
			
		||||
	int			 fd;
 | 
			
		||||
	pid_t			 pid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define IMSGF_HASFD	1
 | 
			
		||||
 | 
			
		||||
struct imsg_hdr {
 | 
			
		||||
	u_int32_t	 type;
 | 
			
		||||
	u_int16_t	 len;
 | 
			
		||||
	u_int16_t	 flags;
 | 
			
		||||
	u_int32_t	 peerid;
 | 
			
		||||
	u_int32_t	 pid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imsg {
 | 
			
		||||
	struct imsg_hdr	 hdr;
 | 
			
		||||
	int		 fd;
 | 
			
		||||
	void		*data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* buffer.c */
 | 
			
		||||
struct buf	*buf_open(size_t);
 | 
			
		||||
struct buf	*buf_dynamic(size_t, size_t);
 | 
			
		||||
int		 buf_add(struct buf *, const void *, size_t);
 | 
			
		||||
void		*buf_reserve(struct buf *, size_t);
 | 
			
		||||
void		*buf_seek(struct buf *, size_t, size_t);
 | 
			
		||||
size_t		 buf_size(struct buf *);
 | 
			
		||||
size_t		 buf_left(struct buf *);
 | 
			
		||||
void		 buf_close(struct msgbuf *, struct buf *);
 | 
			
		||||
int		 buf_write(struct msgbuf *);
 | 
			
		||||
void		 buf_free(struct buf *);
 | 
			
		||||
void		 msgbuf_init(struct msgbuf *);
 | 
			
		||||
void		 msgbuf_clear(struct msgbuf *);
 | 
			
		||||
int		 msgbuf_write(struct msgbuf *);
 | 
			
		||||
 | 
			
		||||
/* imsg.c */
 | 
			
		||||
void	 imsg_init(struct imsgbuf *, int);
 | 
			
		||||
ssize_t	 imsg_read(struct imsgbuf *);
 | 
			
		||||
ssize_t	 imsg_get(struct imsgbuf *, struct imsg *);
 | 
			
		||||
int	 imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
 | 
			
		||||
	    int, void *, u_int16_t);
 | 
			
		||||
int	 imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t,  pid_t,
 | 
			
		||||
	    int, const struct iovec *, int);
 | 
			
		||||
struct buf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t,
 | 
			
		||||
	    u_int16_t);
 | 
			
		||||
int	 imsg_add(struct buf *, void *, u_int16_t);
 | 
			
		||||
void	 imsg_close(struct imsgbuf *, struct buf *);
 | 
			
		||||
void	 imsg_free(struct imsg *);
 | 
			
		||||
int	 imsg_flush(struct imsgbuf *);
 | 
			
		||||
void	 imsg_clear(struct imsgbuf *);
 | 
			
		||||
							
								
								
									
										12
									
								
								server-fn.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								server-fn.c
									
									
									
									
									
								
							@@ -55,18 +55,12 @@ void
 | 
			
		||||
server_write_client(
 | 
			
		||||
    struct client *c, enum msgtype type, const void *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct hdr	 hdr;
 | 
			
		||||
	struct imsgbuf	*ibuf = &c->ibuf;
 | 
			
		||||
 | 
			
		||||
	if (c->flags & CLIENT_BAD)
 | 
			
		||||
		return;
 | 
			
		||||
	log_debug("writing %d to client %d", type, c->fd);
 | 
			
		||||
 | 
			
		||||
	hdr.type = type;
 | 
			
		||||
	hdr.size = len;
 | 
			
		||||
 | 
			
		||||
	buffer_write(c->out, &hdr, sizeof hdr);
 | 
			
		||||
	if (buf != NULL && len > 0)
 | 
			
		||||
		buffer_write(c->out, buf, len);
 | 
			
		||||
	log_debug("writing %d to client %d", type, c->ibuf.fd);
 | 
			
		||||
	imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								server-msg.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								server-msg.c
									
									
									
									
									
								
							@@ -37,45 +37,56 @@ void printflike2 server_msg_command_info(struct cmd_ctx *, const char *, ...);
 | 
			
		||||
int
 | 
			
		||||
server_msg_dispatch(struct client *c)
 | 
			
		||||
{
 | 
			
		||||
	struct hdr		 hdr;
 | 
			
		||||
	struct imsg		 imsg;
 | 
			
		||||
	struct msg_command_data	 commanddata;
 | 
			
		||||
	struct msg_identify_data identifydata;
 | 
			
		||||
	struct msg_resize_data	 resizedata;
 | 
			
		||||
	struct msg_unlock_data	 unlockdata;
 | 
			
		||||
	struct msg_environ_data	 environdata;
 | 
			
		||||
	ssize_t			 n, datalen;
 | 
			
		||||
 | 
			
		||||
        if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
 | 
			
		||||
                return (-1);
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		if (BUFFER_USED(c->in) < sizeof hdr)
 | 
			
		||||
		if ((n = imsg_get(&c->ibuf, &imsg)) == -1)
 | 
			
		||||
			return (-1);
 | 
			
		||||
		if (n == 0)
 | 
			
		||||
			return (0);
 | 
			
		||||
		memcpy(&hdr, BUFFER_OUT(c->in), sizeof hdr);
 | 
			
		||||
		if (BUFFER_USED(c->in) < (sizeof hdr) + hdr.size)
 | 
			
		||||
			return (0);
 | 
			
		||||
		buffer_remove(c->in, sizeof hdr);
 | 
			
		||||
		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
 | 
			
		||||
		switch (hdr.type) {
 | 
			
		||||
		if (imsg.hdr.peerid != PROTOCOL_VERSION) {
 | 
			
		||||
			server_write_client(c, MSG_VERSION, NULL, 0);
 | 
			
		||||
			c->flags |= CLIENT_BAD;
 | 
			
		||||
			imsg_free(&imsg);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_debug("got %d from client %d", imsg.hdr.type, c->ibuf.fd);
 | 
			
		||||
		switch (imsg.hdr.type) {
 | 
			
		||||
		case MSG_COMMAND:
 | 
			
		||||
			if (hdr.size != sizeof commanddata)
 | 
			
		||||
			if (datalen != sizeof commanddata)
 | 
			
		||||
				fatalx("bad MSG_COMMAND size");
 | 
			
		||||
			buffer_read(c->in, &commanddata, sizeof commanddata);
 | 
			
		||||
			memcpy(&commanddata, imsg.data, sizeof commanddata);
 | 
			
		||||
 | 
			
		||||
			server_msg_command(c, &commanddata);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_IDENTIFY:
 | 
			
		||||
			if (hdr.size != sizeof identifydata)
 | 
			
		||||
			if (datalen != sizeof identifydata)
 | 
			
		||||
				fatalx("bad MSG_IDENTIFY size");
 | 
			
		||||
			buffer_read(c->in, &identifydata, sizeof identifydata);
 | 
			
		||||
			memcpy(&identifydata, imsg.data, sizeof identifydata);
 | 
			
		||||
 | 
			
		||||
			server_msg_identify(c, &identifydata);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_RESIZE:
 | 
			
		||||
			if (hdr.size != sizeof resizedata)
 | 
			
		||||
			if (datalen != sizeof resizedata)
 | 
			
		||||
				fatalx("bad MSG_RESIZE size");
 | 
			
		||||
			buffer_read(c->in, &resizedata, sizeof resizedata);
 | 
			
		||||
			memcpy(&resizedata, imsg.data, sizeof resizedata);
 | 
			
		||||
 | 
			
		||||
			server_msg_resize(c, &resizedata);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_EXITING:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_EXITING size");
 | 
			
		||||
 | 
			
		||||
			c->session = NULL;
 | 
			
		||||
@@ -83,9 +94,9 @@ server_msg_dispatch(struct client *c)
 | 
			
		||||
			server_write_client(c, MSG_EXITED, NULL, 0);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_UNLOCK:
 | 
			
		||||
			if (hdr.size != sizeof unlockdata)
 | 
			
		||||
			if (datalen != sizeof unlockdata)
 | 
			
		||||
				fatalx("bad MSG_UNLOCK size");
 | 
			
		||||
			buffer_read(c->in, &unlockdata, sizeof unlockdata);
 | 
			
		||||
			memcpy(&unlockdata, imsg.data, sizeof unlockdata);
 | 
			
		||||
 | 
			
		||||
			unlockdata.pass[(sizeof unlockdata.pass) - 1] = '\0';
 | 
			
		||||
			if (server_unlock(unlockdata.pass) != 0)
 | 
			
		||||
@@ -94,7 +105,7 @@ server_msg_dispatch(struct client *c)
 | 
			
		||||
			server_write_client(c, MSG_EXIT, NULL, 0);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_WAKEUP:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_WAKEUP size");
 | 
			
		||||
 | 
			
		||||
			c->flags &= ~CLIENT_SUSPENDED;
 | 
			
		||||
@@ -102,9 +113,9 @@ server_msg_dispatch(struct client *c)
 | 
			
		||||
			server_redraw_client(c);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_ENVIRON:
 | 
			
		||||
			if (hdr.size != sizeof environdata)
 | 
			
		||||
			if (datalen != sizeof environdata)
 | 
			
		||||
				fatalx("bad MSG_ENVIRON size");
 | 
			
		||||
			buffer_read(c->in, &environdata, sizeof environdata);
 | 
			
		||||
			memcpy(&environdata, imsg.data, sizeof environdata);
 | 
			
		||||
 | 
			
		||||
			environdata.var[(sizeof environdata.var) - 1] = '\0';
 | 
			
		||||
			if (strchr(environdata.var, '=') != NULL)
 | 
			
		||||
@@ -113,6 +124,8 @@ server_msg_dispatch(struct client *c)
 | 
			
		||||
		default:
 | 
			
		||||
			fatalx("unexpected message");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		imsg_free(&imsg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -224,11 +237,6 @@ error:
 | 
			
		||||
void
 | 
			
		||||
server_msg_identify(struct client *c, struct msg_identify_data *data)
 | 
			
		||||
{
 | 
			
		||||
	if (data->version != PROTOCOL_VERSION) {
 | 
			
		||||
		server_write_error(c, "protocol version mismatch");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c->tty.sx = data->sx;
 | 
			
		||||
	c->tty.sy = data->sy;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								server.c
									
									
									
									
									
								
							@@ -85,9 +85,7 @@ server_create_client(int fd)
 | 
			
		||||
		fatal("fcntl failed");
 | 
			
		||||
 | 
			
		||||
	c = xcalloc(1, sizeof *c);
 | 
			
		||||
	c->fd = fd;
 | 
			
		||||
	c->in = buffer_create(BUFSIZ);
 | 
			
		||||
	c->out = buffer_create(BUFSIZ);
 | 
			
		||||
	imsg_init(&c->ibuf, fd);
 | 
			
		||||
 | 
			
		||||
	ARRAY_INIT(&c->prompt_hdata);
 | 
			
		||||
 | 
			
		||||
@@ -672,10 +670,10 @@ server_fill_clients(struct pollfd **pfd)
 | 
			
		||||
		if (c == NULL)
 | 
			
		||||
			(*pfd)->fd = -1;
 | 
			
		||||
		else {
 | 
			
		||||
			(*pfd)->fd = c->fd;
 | 
			
		||||
			(*pfd)->fd = c->ibuf.fd;
 | 
			
		||||
			if (!(c->flags & CLIENT_BAD))
 | 
			
		||||
				(*pfd)->events = POLLIN;
 | 
			
		||||
			if (BUFFER_USED(c->out) > 0)
 | 
			
		||||
				(*pfd)->events |= POLLIN;
 | 
			
		||||
			if (c->ibuf.w.queued > 0)
 | 
			
		||||
				(*pfd)->events |= POLLOUT;
 | 
			
		||||
		}
 | 
			
		||||
		(*pfd)++;
 | 
			
		||||
@@ -718,17 +716,32 @@ server_handle_clients(struct pollfd **pfd)
 | 
			
		||||
		c = ARRAY_ITEM(&clients, i);
 | 
			
		||||
 | 
			
		||||
		if (c != NULL) {
 | 
			
		||||
			if (buffer_poll(*pfd, c->in, c->out) != 0) {
 | 
			
		||||
			if ((*pfd)->revents & (POLLERR|POLLNVAL|POLLHUP)) {
 | 
			
		||||
				server_lost_client(c);
 | 
			
		||||
				(*pfd) += 2;
 | 
			
		||||
				continue;
 | 
			
		||||
			} else if (c->flags & CLIENT_BAD) {
 | 
			
		||||
				if (BUFFER_USED(c->out) == 0)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ((*pfd)->revents & POLLOUT) {
 | 
			
		||||
				if (msgbuf_write(&c->ibuf.w) < 0) {
 | 
			
		||||
					server_lost_client(c);
 | 
			
		||||
					(*pfd) += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (c->flags & CLIENT_BAD) {
 | 
			
		||||
				if (c->ibuf.w.queued == 0)
 | 
			
		||||
					server_lost_client(c);
 | 
			
		||||
				(*pfd) += 2;
 | 
			
		||||
				continue;
 | 
			
		||||
			} else
 | 
			
		||||
				server_msg_dispatch(c);
 | 
			
		||||
			} else if ((*pfd)->revents & POLLIN) {
 | 
			
		||||
				if (server_msg_dispatch(c) != 0) {
 | 
			
		||||
					server_lost_client(c);
 | 
			
		||||
					(*pfd) += 2;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		(*pfd)++;
 | 
			
		||||
 | 
			
		||||
@@ -910,9 +923,8 @@ server_lost_client(struct client *c)
 | 
			
		||||
	if (c->cwd != NULL)
 | 
			
		||||
		xfree(c->cwd);
 | 
			
		||||
 | 
			
		||||
	close(c->fd);
 | 
			
		||||
	buffer_destroy(c->in);
 | 
			
		||||
	buffer_destroy(c->out);
 | 
			
		||||
	close(c->ibuf.fd);
 | 
			
		||||
	imsg_clear(&c->ibuf);
 | 
			
		||||
	xfree(c);
 | 
			
		||||
 | 
			
		||||
	recalculate_sizes();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										112
									
								
								tmux.c
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								tmux.c
									
									
									
									
									
								
							@@ -60,6 +60,7 @@ __dead void	 usage(void);
 | 
			
		||||
char 		*makesockpath(const char *);
 | 
			
		||||
int		 prepare_unlock(enum msgtype *, void **, size_t *, int);
 | 
			
		||||
int		 prepare_cmd(enum msgtype *, void **, size_t *, int, char **);
 | 
			
		||||
int		 dispatch_imsg(struct client_ctx *, int *);
 | 
			
		||||
 | 
			
		||||
__dead void
 | 
			
		||||
usage(void)
 | 
			
		||||
@@ -260,14 +261,13 @@ main(int argc, char **argv)
 | 
			
		||||
 	struct cmd		*cmd;
 | 
			
		||||
	struct pollfd	 	 pfd;
 | 
			
		||||
	enum msgtype		 msg;
 | 
			
		||||
	struct hdr	 	 hdr;
 | 
			
		||||
	struct passwd		*pw;
 | 
			
		||||
	struct msg_print_data	 printdata;
 | 
			
		||||
	char			*s, *path, *label, *home, *cause, **var;
 | 
			
		||||
	char			 cwd[MAXPATHLEN];
 | 
			
		||||
	void			*buf;
 | 
			
		||||
	size_t			 len;
 | 
			
		||||
	int	 		 retcode, opt, flags, unlock, cmdflags = 0;
 | 
			
		||||
	int			 nfds;
 | 
			
		||||
 | 
			
		||||
	unlock = flags = 0;
 | 
			
		||||
	label = path = NULL;
 | 
			
		||||
@@ -493,58 +493,92 @@ main(int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	retcode = 0;
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		pfd.fd = cctx.srv_fd;
 | 
			
		||||
		pfd.fd = cctx.ibuf.fd;
 | 
			
		||||
		pfd.events = POLLIN;
 | 
			
		||||
		if (BUFFER_USED(cctx.srv_out) > 0)
 | 
			
		||||
		if (cctx.ibuf.w.queued != 0)
 | 
			
		||||
			pfd.events |= POLLOUT;
 | 
			
		||||
 | 
			
		||||
		if (poll(&pfd, 1, INFTIM) == -1) {
 | 
			
		||||
		if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
 | 
			
		||||
			if (errno == EAGAIN || errno == EINTR)
 | 
			
		||||
				continue;
 | 
			
		||||
			fatal("poll failed");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
	restart:
 | 
			
		||||
		if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
 | 
			
		||||
		if (nfds == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
 | 
			
		||||
		if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
 | 
			
		||||
			continue;
 | 
			
		||||
		buffer_remove(cctx.srv_in, sizeof hdr);
 | 
			
		||||
 | 
			
		||||
		switch (hdr.type) {
 | 
			
		||||
		case MSG_EXIT:
 | 
			
		||||
		case MSG_SHUTDOWN:
 | 
			
		||||
			goto out;
 | 
			
		||||
		case MSG_ERROR:
 | 
			
		||||
			retcode = 1;
 | 
			
		||||
			/* FALLTHROUGH */
 | 
			
		||||
		case MSG_PRINT:
 | 
			
		||||
			if (hdr.size < sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_PRINT size");
 | 
			
		||||
			buffer_read(cctx.srv_in, &printdata, sizeof printdata);
 | 
			
		||||
		if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
 | 
			
		||||
			fatalx("socket error");
 | 
			
		||||
 | 
			
		||||
			printdata.msg[(sizeof printdata.msg) - 1] = '\0';
 | 
			
		||||
			log_info("%s", printdata.msg);
 | 
			
		||||
			goto restart;
 | 
			
		||||
		case MSG_READY:
 | 
			
		||||
			retcode = client_main(&cctx);
 | 
			
		||||
			goto out;
 | 
			
		||||
		default:
 | 
			
		||||
			fatalx("unexpected command");
 | 
			
		||||
                if (pfd.revents & POLLIN) {
 | 
			
		||||
			if (dispatch_imsg(&cctx, &retcode) != 0)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pfd.revents & POLLOUT) {
 | 
			
		||||
			if (msgbuf_write(&cctx.ibuf.w) < 0)
 | 
			
		||||
				fatalx("msgbuf_write failed");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	options_free(&global_s_options);
 | 
			
		||||
	options_free(&global_w_options);
 | 
			
		||||
 | 
			
		||||
	close(cctx.srv_fd);
 | 
			
		||||
	buffer_destroy(cctx.srv_in);
 | 
			
		||||
	buffer_destroy(cctx.srv_out);
 | 
			
		||||
 | 
			
		||||
	return (retcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
dispatch_imsg(struct client_ctx *cctx, int *retcode)
 | 
			
		||||
{
 | 
			
		||||
	struct imsg		imsg;
 | 
			
		||||
	ssize_t			n, datalen;
 | 
			
		||||
	struct msg_print_data	printdata;
 | 
			
		||||
 | 
			
		||||
        if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0)
 | 
			
		||||
		fatalx("imsg_read failed");
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
 | 
			
		||||
			fatalx("imsg_get failed");
 | 
			
		||||
		if (n == 0)
 | 
			
		||||
			return (0);
 | 
			
		||||
		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
 | 
			
		||||
		switch (imsg.hdr.type) {
 | 
			
		||||
		case MSG_EXIT:
 | 
			
		||||
		case MSG_SHUTDOWN:
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_EXIT size");
 | 
			
		||||
 | 
			
		||||
			return (-1);
 | 
			
		||||
		case MSG_ERROR:
 | 
			
		||||
			*retcode = 1;
 | 
			
		||||
			/* FALLTHROUGH */
 | 
			
		||||
		case MSG_PRINT:
 | 
			
		||||
			if (datalen != sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_PRINT size");
 | 
			
		||||
			memcpy(&printdata, imsg.data, sizeof printdata);
 | 
			
		||||
			printdata.msg[(sizeof printdata.msg) - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
			log_info("%s", printdata.msg);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_READY:
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_READY size");
 | 
			
		||||
 | 
			
		||||
			*retcode = client_main(cctx);
 | 
			
		||||
			return (-1);
 | 
			
		||||
		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);
 | 
			
		||||
		default:
 | 
			
		||||
			fatalx("unexpected message");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		imsg_free(&imsg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								tmux.h
									
									
									
									
									
								
							@@ -19,12 +19,13 @@
 | 
			
		||||
#ifndef TMUX_H
 | 
			
		||||
#define TMUX_H
 | 
			
		||||
 | 
			
		||||
#define PROTOCOL_VERSION -15
 | 
			
		||||
#define PROTOCOL_VERSION 1
 | 
			
		||||
 | 
			
		||||
#include <sys/param.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/tree.h>
 | 
			
		||||
#include <sys/uio.h>
 | 
			
		||||
 | 
			
		||||
#include <bitstring.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
@@ -37,6 +38,7 @@
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
 | 
			
		||||
#include "array.h"
 | 
			
		||||
#include "imsg.h"
 | 
			
		||||
 | 
			
		||||
extern char    *__progname;
 | 
			
		||||
extern char   **environ;
 | 
			
		||||
@@ -303,23 +305,16 @@ enum msgtype {
 | 
			
		||||
	MSG_SHUTDOWN,
 | 
			
		||||
	MSG_SUSPEND,
 | 
			
		||||
	MSG_UNLOCK,
 | 
			
		||||
	MSG_VERSION,
 | 
			
		||||
	MSG_WAKEUP,
 | 
			
		||||
	MSG_ENVIRON
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Message header and data. 
 | 
			
		||||
 * Message data.
 | 
			
		||||
 *
 | 
			
		||||
 * Don't forget to bump PROTOCOL_VERSION if any of these change!
 | 
			
		||||
 *
 | 
			
		||||
 * Changing sizeof (struct hdr) or sizeof (struct msg_identify_data) will make
 | 
			
		||||
 * the tmux client hang even if the protocol version is bumped.
 | 
			
		||||
 */
 | 
			
		||||
struct hdr {
 | 
			
		||||
	enum msgtype	type;
 | 
			
		||||
	size_t		size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct msg_print_data {
 | 
			
		||||
	char		msg[PRINT_LENGTH];
 | 
			
		||||
};
 | 
			
		||||
@@ -334,7 +329,6 @@ struct msg_command_data {
 | 
			
		||||
 | 
			
		||||
struct msg_identify_data {
 | 
			
		||||
	char		tty[TTY_NAME_MAX];
 | 
			
		||||
	int	        version;
 | 
			
		||||
 | 
			
		||||
	char		cwd[MAXPATHLEN];
 | 
			
		||||
 | 
			
		||||
@@ -908,9 +902,7 @@ struct tty_ctx {
 | 
			
		||||
 | 
			
		||||
/* Client connection. */
 | 
			
		||||
struct client {
 | 
			
		||||
	int		 fd;
 | 
			
		||||
	struct buffer	*in;
 | 
			
		||||
	struct buffer	*out;
 | 
			
		||||
	struct imsgbuf	 ibuf;
 | 
			
		||||
 | 
			
		||||
	struct environ	 environ;
 | 
			
		||||
 | 
			
		||||
@@ -958,9 +950,7 @@ ARRAY_DECL(clients, struct client *);
 | 
			
		||||
 | 
			
		||||
/* Client context. */
 | 
			
		||||
struct client_ctx {
 | 
			
		||||
	int		 srv_fd;
 | 
			
		||||
	struct buffer	*srv_in;
 | 
			
		||||
	struct buffer	*srv_out;
 | 
			
		||||
	struct imsgbuf	 ibuf;
 | 
			
		||||
 | 
			
		||||
	enum {
 | 
			
		||||
		CCTX_DETACH,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user