Commit Diff


commit - 25b639dfa175a8a6684ae2c8666a270fe682523a
commit + 9822808d41d777c56c4d846cd5c6dead306bcc4e
blob - fc8ef7dbd7609263755a10aec3f4dfb6ab8d94fb
blob + c3a15aeaba04a6f9a76cd10b8bae921f61396e63
--- compat/imsg-buffer.c
+++ compat/imsg-buffer.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 claudio Exp $	*/
+/*	$OpenBSD: imsg-buffer.c,v 1.36 2025/08/25 08:29:49 claudio Exp $	*/
 
 /*
  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
@@ -32,10 +32,14 @@
 #include "got_compat.h"
 #include "imsg.h"
 
+struct ibufqueue {
+	TAILQ_HEAD(, ibuf)	bufs;
+	uint32_t		queued;
+};
+
 struct msgbuf {
-	TAILQ_HEAD(, ibuf)	 bufs;
-	TAILQ_HEAD(, ibuf)	 rbufs;
-	uint32_t		 queued;
+	struct ibufqueue	 bufs;
+	struct ibufqueue	 rbufs;
 	char			*rbuf;
 	struct ibuf		*rpmsg;
 	struct ibuf		*(*readhdr)(struct ibuf *, void *, int *);
@@ -44,10 +48,8 @@ struct msgbuf {
 	size_t			 hdrsize;
 };
 
-static void	msgbuf_read_enqueue(struct msgbuf *, struct ibuf *);
-static void	msgbuf_enqueue(struct msgbuf *, struct ibuf *);
-static void	msgbuf_dequeue(struct msgbuf *, struct ibuf *);
 static void	msgbuf_drain(struct msgbuf *, size_t);
+static void	ibufq_init(struct ibufqueue *);
 
 #define	IBUF_FD_MARK_ON_STACK	-2
 
@@ -136,6 +138,9 @@ ibuf_add(struct ibuf *buf, const void *data, size_t le
 {
 	void *b;
 
+	if (len == 0)
+		return (0);
+
 	if ((b = ibuf_reserve(buf, len)) == NULL)
 		return (-1);
 
@@ -232,9 +237,31 @@ ibuf_add_zero(struct ibuf *buf, size_t len)
 {
 	void *b;
 
+	if (len == 0)
+		return (0);
+
 	if ((b = ibuf_reserve(buf, len)) == NULL)
 		return (-1);
 	memset(b, 0, len);
+	return (0);
+}
+
+int
+ibuf_add_strbuf(struct ibuf *buf, const char *str, size_t len)
+{
+	char *b;
+	size_t n;
+
+	if ((b = ibuf_reserve(buf, len)) == NULL)
+		return (-1);
+
+	n = strlcpy(b, str, len);
+	if (n >= len) {
+		/* also covers the case where len == 0 */
+		errno = EOVERFLOW;
+		return (-1);
+	}
+	memset(b + n, 0, len - n);
 	return (0);
 }
 
@@ -259,6 +286,8 @@ ibuf_set(struct ibuf *buf, size_t pos, const void *dat
 	if ((b = ibuf_seek(buf, pos, len)) == NULL)
 		return (-1);
 
+	if (len == 0)
+		return (0);
 	memcpy(b, data, len);
 	return (0);
 }
@@ -341,6 +370,22 @@ ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t va
 	return (ibuf_set(buf, pos, &value, sizeof(value)));
 }
 
+int
+ibuf_set_maxsize(struct ibuf *buf, size_t max)
+{
+	if (buf->fd == IBUF_FD_MARK_ON_STACK) {
+		/* can't fiddle with stack buffers */
+		errno = EINVAL;
+		return (-1);
+	}
+	if (max > buf->max) {
+		errno = ERANGE;
+		return (-1);
+	}
+	buf->max = max;
+	return (0);
+}
+
 void *
 ibuf_data(const struct ibuf *buf)
 {
@@ -386,7 +431,7 @@ ibuf_rewind(struct ibuf *buf)
 void
 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
 {
-	msgbuf_enqueue(msgbuf, buf);
+	ibufq_push(&msgbuf->bufs, buf);
 }
 
 void
@@ -502,6 +547,24 @@ ibuf_get_string(struct ibuf *buf, size_t len)
 }
 
 int
+ibuf_get_strbuf(struct ibuf *buf, char *str, size_t len)
+{
+	if (len == 0) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (ibuf_get(buf, str, len) == -1)
+		return -1;
+	if (str[len - 1] != '\0') {
+		str[len - 1] = '\0';
+		errno = EOVERFLOW;
+		return -1;
+	}
+	return 0;
+}
+
+int
 ibuf_skip(struct ibuf *buf, size_t len)
 {
 	if (ibuf_size(buf) < len) {
@@ -516,6 +579,8 @@ ibuf_skip(struct ibuf *buf, size_t len)
 void
 ibuf_free(struct ibuf *buf)
 {
+	int save_errno = errno;
+
 	if (buf == NULL)
 		return;
 	/* if buf lives on the stack abort before causing more harm */
@@ -525,6 +590,7 @@ ibuf_free(struct ibuf *buf)
 		close(buf->fd);
 	freezero(buf->buf, buf->size);
 	free(buf);
+	errno = save_errno;
 }
 
 int
@@ -566,9 +632,8 @@ msgbuf_new(void)
 
 	if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
 		return (NULL);
-	msgbuf->queued = 0;
-	TAILQ_INIT(&msgbuf->bufs);
-	TAILQ_INIT(&msgbuf->rbufs);
+	ibufq_init(&msgbuf->bufs);
+	ibufq_init(&msgbuf->rbufs);
 
 	return msgbuf;
 }
@@ -615,24 +680,17 @@ msgbuf_free(struct msgbuf *msgbuf)
 uint32_t
 msgbuf_queuelen(struct msgbuf *msgbuf)
 {
-	return (msgbuf->queued);
+	return ibufq_queuelen(&msgbuf->bufs);
 }
 
 void
 msgbuf_clear(struct msgbuf *msgbuf)
 {
-	struct ibuf	*buf;
-
 	/* write side */
-	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
-		msgbuf_dequeue(msgbuf, buf);
-	msgbuf->queued = 0;
+	ibufq_flush(&msgbuf->bufs);
 
 	/* read side */
-	while ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) {
-		TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
-		ibuf_free(buf);
-	}
+	ibufq_flush(&msgbuf->rbufs);
 	msgbuf->roff = 0;
 	ibuf_free(msgbuf->rpmsg);
 	msgbuf->rpmsg = NULL;
@@ -641,11 +699,13 @@ msgbuf_clear(struct msgbuf *msgbuf)
 struct ibuf *
 msgbuf_get(struct msgbuf *msgbuf)
 {
-	struct ibuf	*buf;
+	return ibufq_pop(&msgbuf->rbufs);
+}
 
-	if ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL)
-		TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
-	return buf;
+void
+msgbuf_concat(struct msgbuf *msgbuf, struct ibufqueue *from)
+{
+	ibufq_concat(&msgbuf->bufs, from);
 }
 
 int
@@ -657,7 +717,7 @@ ibuf_write(int fd, struct msgbuf *msgbuf)
 	ssize_t	n;
 
 	memset(&iov, 0, sizeof(iov));
-	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+	TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
 		if (i >= IOV_MAX)
 			break;
 		iov[i].iov_base = ibuf_data(buf);
@@ -698,7 +758,7 @@ msgbuf_write(int fd, struct msgbuf *msgbuf)
 	memset(&iov, 0, sizeof(iov));
 	memset(&msg, 0, sizeof(msg));
 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
-	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
+	TAILQ_FOREACH(buf, &msgbuf->bufs.bufs, entry) {
 		if (i >= IOV_MAX)
 			break;
 		if (i > 0 && buf->fd != -1)
@@ -781,7 +841,7 @@ ibuf_read_process(struct msgbuf *msgbuf, int fd)
 			goto fail;
 
 		if (ibuf_left(msgbuf->rpmsg) == 0) {
-			msgbuf_read_enqueue(msgbuf, msgbuf->rpmsg);
+			ibufq_push(&msgbuf->rbufs, msgbuf->rpmsg);
 			msgbuf->rpmsg = NULL;
 		}
 	} while (ibuf_size(&rbuf) > 0);
@@ -910,46 +970,94 @@ again:
 }
 
 static void
-msgbuf_read_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
+msgbuf_drain(struct msgbuf *msgbuf, size_t n)
 {
-	/* if buf lives on the stack abort before causing more harm */
-	if (buf->fd == IBUF_FD_MARK_ON_STACK)
-		abort();
-	TAILQ_INSERT_TAIL(&msgbuf->rbufs, buf, entry);
+	struct ibuf	*buf;
+
+	while ((buf = TAILQ_FIRST(&msgbuf->bufs.bufs)) != NULL) {
+		if (n >= ibuf_size(buf)) {
+			n -= ibuf_size(buf);
+			TAILQ_REMOVE(&msgbuf->bufs.bufs, buf, entry);
+			msgbuf->bufs.queued--;
+			ibuf_free(buf);
+		} else {
+			buf->rpos += n;
+			return;
+		}
+	}
 }
 
 static void
-msgbuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
+ibufq_init(struct ibufqueue *bufq)
 {
+	TAILQ_INIT(&bufq->bufs);
+	bufq->queued = 0;
+}
+
+struct ibufqueue *
+ibufq_new(void)
+{
+	struct ibufqueue *bufq;
+
+	if ((bufq = calloc(1, sizeof(*bufq))) == NULL)
+		return NULL;
+	ibufq_init(bufq);
+	return bufq;
+}
+
+void
+ibufq_free(struct ibufqueue *bufq)
+{
+	if (bufq == NULL)
+		return;
+	ibufq_flush(bufq);
+	free(bufq);
+}
+
+struct ibuf *
+ibufq_pop(struct ibufqueue *bufq)
+{
+	struct ibuf *buf;
+
+	if ((buf = TAILQ_FIRST(&bufq->bufs)) == NULL)
+		return NULL;
+	TAILQ_REMOVE(&bufq->bufs, buf, entry);
+	bufq->queued--;
+	return buf;
+}
+
+void
+ibufq_push(struct ibufqueue *bufq, struct ibuf *buf)
+{
 	/* if buf lives on the stack abort before causing more harm */
 	if (buf->fd == IBUF_FD_MARK_ON_STACK)
 		abort();
-	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
-	msgbuf->queued++;
+	TAILQ_INSERT_TAIL(&bufq->bufs, buf, entry);
+	bufq->queued++;
 }
 
-static void
-msgbuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
+uint32_t
+ibufq_queuelen(struct ibufqueue *bufq)
 {
-	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
-	msgbuf->queued--;
-	ibuf_free(buf);
+	return (bufq->queued);
 }
 
-static void
-msgbuf_drain(struct msgbuf *msgbuf, size_t n)
+void
+ibufq_concat(struct ibufqueue *to, struct ibufqueue *from)
 {
-	struct ibuf	*buf, *next;
+	to->queued += from->queued;
+	TAILQ_CONCAT(&to->bufs, &from->bufs, entry);
+	from->queued = 0;
+}
 
-	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
-	    buf = next) {
-		next = TAILQ_NEXT(buf, entry);
-		if (n >= ibuf_size(buf)) {
-			n -= ibuf_size(buf);
-			msgbuf_dequeue(msgbuf, buf);
-		} else {
-			buf->rpos += n;
-			n = 0;
-		}
+void
+ibufq_flush(struct ibufqueue *bufq)
+{
+	struct ibuf *buf;
+
+	while ((buf = TAILQ_FIRST(&bufq->bufs)) != NULL) {
+		TAILQ_REMOVE(&bufq->bufs, buf, entry);
+		ibuf_free(buf);
 	}
+	bufq->queued = 0;
 }
blob - a0f242a4b0637ab5f82769ab8f97af05293cccb5
blob + 5be3d72bb78affb96bab7ff26b0cd4d892f0865b
--- compat/imsg.c
+++ compat/imsg.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg.c,v 1.38 2024/11/29 04:35:13 tb Exp $	*/
+/*	$OpenBSD: imsg.c,v 1.42 2025/06/16 13:56:11 claudio Exp $	*/
 
 /*
  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
@@ -24,6 +24,7 @@
 
 #include <errno.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -57,13 +58,18 @@ imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf)
 }
 
 int
-imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t maxsize)
+imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t max)
 {
-	if (maxsize < IMSG_HEADER_SIZE || maxsize & IMSG_FD_MARK) {
+	if (max > UINT32_MAX - IMSG_HEADER_SIZE) {
+		errno = ERANGE;
+		return (-1);
+	}
+	max += IMSG_HEADER_SIZE;
+	if (max & IMSG_FD_MARK) {
 		errno = EINVAL;
 		return (-1);
 	}
-	imsgbuf->maxsize = maxsize;
+	imsgbuf->maxsize = max;
 	return (0);
 }
 
@@ -108,13 +114,46 @@ imsgbuf_queuelen(struct imsgbuf *imsgbuf)
 	return msgbuf_queuelen(imsgbuf->w);
 }
 
+int
+imsgbuf_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
+{
+	struct imsg	 m;
+	struct ibuf	*buf;
+
+	if ((buf = msgbuf_get(imsgbuf->w)) == NULL)
+		return (0);
+
+	if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1)
+		return (-1);
+
+	if (ibuf_size(buf))
+		m.data = ibuf_data(buf);
+	else
+		m.data = NULL;
+	m.buf = buf;
+	m.hdr.len &= ~IMSG_FD_MARK;
+
+	*imsg = m;
+	return (1);
+}
+
 ssize_t
 imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
 {
-	struct imsg		 m;
-	struct ibuf		*buf;
+	int rv;
 
-	if ((buf = msgbuf_get(imsgbuf->w)) == NULL)
+	if ((rv = imsgbuf_get(imsgbuf, imsg)) != 1)
+		return rv;
+	return (imsg_get_len(imsg) + IMSG_HEADER_SIZE);
+}
+
+int
+imsg_ibufq_pop(struct ibufqueue *bufq, struct imsg *imsg)
+{
+	struct imsg	 m;
+	struct ibuf	*buf;
+
+	if ((buf = ibufq_pop(bufq)) == NULL)
 		return (0);
 
 	if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1)
@@ -128,9 +167,17 @@ imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
 	m.hdr.len &= ~IMSG_FD_MARK;
 
 	*imsg = m;
-	return (ibuf_size(buf) + IMSG_HEADER_SIZE);
+	return (1);
 }
 
+void
+imsg_ibufq_push(struct ibufqueue *bufq, struct imsg *imsg)
+{
+	ibuf_rewind(imsg->buf);
+	ibufq_push(bufq, imsg->buf);
+	memset(imsg, 0, sizeof(*imsg));
+}
+
 int
 imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
 {
@@ -152,10 +199,22 @@ imsg_get_data(struct imsg *imsg, void *data, size_t le
 		errno = EBADMSG;
 		return (-1);
 	}
+	return ibuf_get(imsg->buf, data, len);
+}
+
+int
+imsg_get_buf(struct imsg *imsg, void *data, size_t len)
+{
 	return ibuf_get(imsg->buf, data, len);
 }
 
 int
+imsg_get_strbuf(struct imsg *imsg, char *str, size_t len)
+{
+	return ibuf_get_strbuf(imsg->buf, str, len);
+}
+
+int
 imsg_get_fd(struct imsg *imsg)
 {
 	return ibuf_fd_get(imsg->buf);
@@ -192,15 +251,19 @@ imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, u
 	struct ibuf	*wbuf;
 
 	if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
-		return (-1);
+		goto fail;
 
-	if (imsg_add(wbuf, data, datalen) == -1)
-		return (-1);
+	if (ibuf_add(wbuf, data, datalen) == -1)
+		goto fail;
 
 	ibuf_fd_set(wbuf, fd);
 	imsg_close(imsgbuf, wbuf);
 
 	return (1);
+
+ fail:
+	ibuf_free(wbuf);
+	return (-1);
 }
 
 int
@@ -215,16 +278,20 @@ imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, 
 		datalen += iov[i].iov_len;
 
 	if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
-		return (-1);
+		goto fail;
 
 	for (i = 0; i < iovcnt; i++)
-		if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
-			return (-1);
+		if (ibuf_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
+			goto fail;
 
 	ibuf_fd_set(wbuf, fd);
 	imsg_close(imsgbuf, wbuf);
 
 	return (1);
+
+ fail:
+	ibuf_free(wbuf);
+	return (-1);
 }
 
 /*
@@ -237,7 +304,6 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t ty
 {
 	struct ibuf	*hdrbuf = NULL;
 	struct imsg_hdr	 hdr;
-	int save_errno;
 
 	if (ibuf_size(buf) + IMSG_HEADER_SIZE > imsgbuf->maxsize) {
 		errno = ERANGE;
@@ -252,7 +318,7 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t ty
 
 	if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
 		goto fail;
-	if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
+	if (ibuf_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
 		goto fail;
 
 	ibuf_close(imsgbuf->w, hdrbuf);
@@ -260,10 +326,8 @@ imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t ty
 	return (1);
 
  fail:
-	save_errno = errno;
 	ibuf_free(buf);
 	ibuf_free(hdrbuf);
-	errno = save_errno;
 	return (-1);
 }
 
@@ -308,17 +372,21 @@ imsg_create(struct imsgbuf *imsgbuf, uint32_t type, ui
 		return (NULL);
 	}
 
+	hdr.len = 0;
 	hdr.type = type;
 	hdr.peerid = id;
 	if ((hdr.pid = pid) == 0)
 		hdr.pid = imsgbuf->pid;
-	if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL) {
-		return (NULL);
-	}
-	if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
-		return (NULL);
+	if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL)
+		goto fail;
+	if (ibuf_add(wbuf, &hdr, sizeof(hdr)) == -1)
+		goto fail;
 
 	return (wbuf);
+
+ fail:
+	ibuf_free(wbuf);
+	return (NULL);
 }
 
 int
@@ -350,6 +418,16 @@ imsg_free(struct imsg *imsg)
 	ibuf_free(imsg->buf);
 }
 
+int
+imsg_set_maxsize(struct ibuf *msg, size_t max)
+{
+	if (max > UINT32_MAX - IMSG_HEADER_SIZE) {
+		errno = ERANGE;
+		return (-1);
+	}
+	return ibuf_set_maxsize(msg, max + IMSG_HEADER_SIZE);
+}
+
 static struct ibuf *
 imsg_parse_hdr(struct ibuf *buf, void *arg, int *fd)
 {
blob - 462bfc97ffccdfc7bc6deae66c8b185c4ae1621d
blob + d18adb4939c2f344312f662508ce6a9a6ce67c86
--- compat/imsg.h
+++ compat/imsg.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: imsg.h,v 1.19 2024/11/26 13:57:31 claudio Exp $	*/
+/*	$OpenBSD: imsg.h,v 1.24 2025/06/05 08:55:07 tb Exp $	*/
 
 /*
  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
@@ -23,6 +23,9 @@
 #define _IMSG_H_
 
 #include <sys/types.h>
+#include <sys/queue.h>
+#include <stddef.h>
+#include <stdint.h>
 
 #define IBUF_READ_SIZE		65535
 #define IMSG_HEADER_SIZE	sizeof(struct imsg_hdr)
@@ -38,6 +41,7 @@ struct ibuf {
 	int			 fd;
 };
 
+struct ibufqueue;
 struct msgbuf;
 
 struct imsgbuf {
@@ -76,6 +80,7 @@ int		 ibuf_add_n64(struct ibuf *, uint64_t);
 int		 ibuf_add_h16(struct ibuf *, uint64_t);
 int		 ibuf_add_h32(struct ibuf *, uint64_t);
 int		 ibuf_add_h64(struct ibuf *, uint64_t);
+int		 ibuf_add_strbuf(struct ibuf *, const char *, size_t);
 void		*ibuf_reserve(struct ibuf *, size_t);
 void		*ibuf_seek(struct ibuf *, size_t, size_t);
 int		 ibuf_set(struct ibuf *, size_t, const void *, size_t);
@@ -86,6 +91,7 @@ int		 ibuf_set_n64(struct ibuf *, size_t, uint64_t);
 int		 ibuf_set_h16(struct ibuf *, size_t, uint64_t);
 int		 ibuf_set_h32(struct ibuf *, size_t, uint64_t);
 int		 ibuf_set_h64(struct ibuf *, size_t, uint64_t);
+int		 ibuf_set_maxsize(struct ibuf *, size_t);
 void		*ibuf_data(const struct ibuf *);
 size_t		 ibuf_size(const struct ibuf *);
 size_t		 ibuf_left(const struct ibuf *);
@@ -104,6 +110,7 @@ int		 ibuf_get_h16(struct ibuf *, uint16_t *);
 int		 ibuf_get_h32(struct ibuf *, uint32_t *);
 int		 ibuf_get_h64(struct ibuf *, uint64_t *);
 char		*ibuf_get_string(struct ibuf *, size_t);
+int		 ibuf_get_strbuf(struct ibuf *, char *, size_t);
 int		 ibuf_skip(struct ibuf *, size_t);
 void		 ibuf_free(struct ibuf *);
 int		 ibuf_fd_avail(struct ibuf *);
@@ -114,6 +121,7 @@ struct msgbuf	*msgbuf_new_reader(size_t,
 		    struct ibuf *(*)(struct ibuf *, void *, int *), void *);
 void		 msgbuf_free(struct msgbuf *);
 void		 msgbuf_clear(struct msgbuf *);
+void		 msgbuf_concat(struct msgbuf *, struct ibufqueue *);
 uint32_t	 msgbuf_queuelen(struct msgbuf *);
 int		 ibuf_write(int, struct msgbuf *);
 int		 msgbuf_write(int, struct msgbuf *);
@@ -121,6 +129,14 @@ int		 ibuf_read(int, struct msgbuf *);
 int		 msgbuf_read(int, struct msgbuf *);
 struct ibuf	*msgbuf_get(struct msgbuf *);
 
+struct ibufqueue	*ibufq_new(void);
+void		 ibufq_free(struct ibufqueue *);
+struct ibuf	*ibufq_pop(struct ibufqueue *bufq);
+void		 ibufq_push(struct ibufqueue *, struct ibuf *);
+uint32_t	 ibufq_queuelen(struct ibufqueue *);
+void		 ibufq_concat(struct ibufqueue *, struct ibufqueue *);
+void		 ibufq_flush(struct ibufqueue *);
+
 /* imsg.c */
 int	 imsgbuf_init(struct imsgbuf *, int);
 void	 imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf);
@@ -130,9 +146,14 @@ int	 imsgbuf_write(struct imsgbuf *);
 int	 imsgbuf_flush(struct imsgbuf *);
 void	 imsgbuf_clear(struct imsgbuf *);
 uint32_t imsgbuf_queuelen(struct imsgbuf *);
+int	 imsgbuf_get(struct imsgbuf *, struct imsg *);
 ssize_t	 imsg_get(struct imsgbuf *, struct imsg *);
+int	 imsg_ibufq_pop(struct ibufqueue *, struct imsg *);
+void	 imsg_ibufq_push(struct ibufqueue *, struct imsg *);
 int	 imsg_get_ibuf(struct imsg *, struct ibuf *);
 int	 imsg_get_data(struct imsg *, void *, size_t);
+int	 imsg_get_buf(struct imsg *, void *, size_t);
+int	 imsg_get_strbuf(struct imsg *, char *, size_t);
 int	 imsg_get_fd(struct imsg *);
 uint32_t imsg_get_id(struct imsg *);
 size_t	 imsg_get_len(struct imsg *);
@@ -149,5 +170,6 @@ struct ibuf *imsg_create(struct imsgbuf *, uint32_t, u
 int	 imsg_add(struct ibuf *, const void *, size_t);
 void	 imsg_close(struct imsgbuf *, struct ibuf *);
 void	 imsg_free(struct imsg *);
+int	 imsg_set_maxsize(struct ibuf *, size_t);
 
 #endif