make got-send-pack clear its imsgbuf on exit
[got-portable.git] / compat / imsg-buffer.c
blobfc8ef7dbd7609263755a10aec3f4dfb6ab8d94fb
1 /* $OpenBSD: imsg-buffer.c,v 1.31 2024/11/26 13:57:31 claudio Exp $ */
3 /*
4 * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/socket.h>
23 #include <sys/uio.h>
25 #include <limits.h>
26 #include <errno.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
32 #include "got_compat.h"
33 #include "imsg.h"
35 struct msgbuf {
36 TAILQ_HEAD(, ibuf) bufs;
37 TAILQ_HEAD(, ibuf) rbufs;
38 uint32_t queued;
39 char *rbuf;
40 struct ibuf *rpmsg;
41 struct ibuf *(*readhdr)(struct ibuf *, void *, int *);
42 void *rarg;
43 size_t roff;
44 size_t hdrsize;
47 static void msgbuf_read_enqueue(struct msgbuf *, struct ibuf *);
48 static void msgbuf_enqueue(struct msgbuf *, struct ibuf *);
49 static void msgbuf_dequeue(struct msgbuf *, struct ibuf *);
50 static void msgbuf_drain(struct msgbuf *, size_t);
52 #define IBUF_FD_MARK_ON_STACK -2
54 struct ibuf *
55 ibuf_open(size_t len)
57 struct ibuf *buf;
59 if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
60 return (NULL);
61 if (len > 0) {
62 if ((buf->buf = calloc(len, 1)) == NULL) {
63 free(buf);
64 return (NULL);
67 buf->size = buf->max = len;
68 buf->fd = -1;
70 return (buf);
73 struct ibuf *
74 ibuf_dynamic(size_t len, size_t max)
76 struct ibuf *buf;
78 if (max == 0 || max < len) {
79 errno = EINVAL;
80 return (NULL);
83 if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
84 return (NULL);
85 if (len > 0) {
86 if ((buf->buf = calloc(len, 1)) == NULL) {
87 free(buf);
88 return (NULL);
91 buf->size = len;
92 buf->max = max;
93 buf->fd = -1;
95 return (buf);
98 void *
99 ibuf_reserve(struct ibuf *buf, size_t len)
101 void *b;
103 if (len > SIZE_MAX - buf->wpos) {
104 errno = ERANGE;
105 return (NULL);
107 if (buf->fd == IBUF_FD_MARK_ON_STACK) {
108 /* can not grow stack buffers */
109 errno = EINVAL;
110 return (NULL);
113 if (buf->wpos + len > buf->size) {
114 unsigned char *nb;
116 /* check if buffer is allowed to grow */
117 if (buf->wpos + len > buf->max) {
118 errno = ERANGE;
119 return (NULL);
121 nb = realloc(buf->buf, buf->wpos + len);
122 if (nb == NULL)
123 return (NULL);
124 memset(nb + buf->size, 0, buf->wpos + len - buf->size);
125 buf->buf = nb;
126 buf->size = buf->wpos + len;
129 b = buf->buf + buf->wpos;
130 buf->wpos += len;
131 return (b);
135 ibuf_add(struct ibuf *buf, const void *data, size_t len)
137 void *b;
139 if ((b = ibuf_reserve(buf, len)) == NULL)
140 return (-1);
142 memcpy(b, data, len);
143 return (0);
147 ibuf_add_ibuf(struct ibuf *buf, const struct ibuf *from)
149 return ibuf_add(buf, ibuf_data(from), ibuf_size(from));
153 ibuf_add_n8(struct ibuf *buf, uint64_t value)
155 uint8_t v;
157 if (value > UINT8_MAX) {
158 errno = EINVAL;
159 return (-1);
161 v = value;
162 return ibuf_add(buf, &v, sizeof(v));
166 ibuf_add_n16(struct ibuf *buf, uint64_t value)
168 uint16_t v;
170 if (value > UINT16_MAX) {
171 errno = EINVAL;
172 return (-1);
174 v = htobe16(value);
175 return ibuf_add(buf, &v, sizeof(v));
179 ibuf_add_n32(struct ibuf *buf, uint64_t value)
181 uint32_t v;
183 if (value > UINT32_MAX) {
184 errno = EINVAL;
185 return (-1);
187 v = htobe32(value);
188 return ibuf_add(buf, &v, sizeof(v));
192 ibuf_add_n64(struct ibuf *buf, uint64_t value)
194 value = htobe64(value);
195 return ibuf_add(buf, &value, sizeof(value));
199 ibuf_add_h16(struct ibuf *buf, uint64_t value)
201 uint16_t v;
203 if (value > UINT16_MAX) {
204 errno = EINVAL;
205 return (-1);
207 v = value;
208 return ibuf_add(buf, &v, sizeof(v));
212 ibuf_add_h32(struct ibuf *buf, uint64_t value)
214 uint32_t v;
216 if (value > UINT32_MAX) {
217 errno = EINVAL;
218 return (-1);
220 v = value;
221 return ibuf_add(buf, &v, sizeof(v));
225 ibuf_add_h64(struct ibuf *buf, uint64_t value)
227 return ibuf_add(buf, &value, sizeof(value));
231 ibuf_add_zero(struct ibuf *buf, size_t len)
233 void *b;
235 if ((b = ibuf_reserve(buf, len)) == NULL)
236 return (-1);
237 memset(b, 0, len);
238 return (0);
241 void *
242 ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
244 /* only allow seeking between rpos and wpos */
245 if (ibuf_size(buf) < pos || SIZE_MAX - pos < len ||
246 ibuf_size(buf) < pos + len) {
247 errno = ERANGE;
248 return (NULL);
251 return (buf->buf + buf->rpos + pos);
255 ibuf_set(struct ibuf *buf, size_t pos, const void *data, size_t len)
257 void *b;
259 if ((b = ibuf_seek(buf, pos, len)) == NULL)
260 return (-1);
262 memcpy(b, data, len);
263 return (0);
267 ibuf_set_n8(struct ibuf *buf, size_t pos, uint64_t value)
269 uint8_t v;
271 if (value > UINT8_MAX) {
272 errno = EINVAL;
273 return (-1);
275 v = value;
276 return (ibuf_set(buf, pos, &v, sizeof(v)));
280 ibuf_set_n16(struct ibuf *buf, size_t pos, uint64_t value)
282 uint16_t v;
284 if (value > UINT16_MAX) {
285 errno = EINVAL;
286 return (-1);
288 v = htobe16(value);
289 return (ibuf_set(buf, pos, &v, sizeof(v)));
293 ibuf_set_n32(struct ibuf *buf, size_t pos, uint64_t value)
295 uint32_t v;
297 if (value > UINT32_MAX) {
298 errno = EINVAL;
299 return (-1);
301 v = htobe32(value);
302 return (ibuf_set(buf, pos, &v, sizeof(v)));
306 ibuf_set_n64(struct ibuf *buf, size_t pos, uint64_t value)
308 value = htobe64(value);
309 return (ibuf_set(buf, pos, &value, sizeof(value)));
313 ibuf_set_h16(struct ibuf *buf, size_t pos, uint64_t value)
315 uint16_t v;
317 if (value > UINT16_MAX) {
318 errno = EINVAL;
319 return (-1);
321 v = value;
322 return (ibuf_set(buf, pos, &v, sizeof(v)));
326 ibuf_set_h32(struct ibuf *buf, size_t pos, uint64_t value)
328 uint32_t v;
330 if (value > UINT32_MAX) {
331 errno = EINVAL;
332 return (-1);
334 v = value;
335 return (ibuf_set(buf, pos, &v, sizeof(v)));
339 ibuf_set_h64(struct ibuf *buf, size_t pos, uint64_t value)
341 return (ibuf_set(buf, pos, &value, sizeof(value)));
344 void *
345 ibuf_data(const struct ibuf *buf)
347 return (buf->buf + buf->rpos);
350 size_t
351 ibuf_size(const struct ibuf *buf)
353 return (buf->wpos - buf->rpos);
356 size_t
357 ibuf_left(const struct ibuf *buf)
359 /* on stack buffers have no space left */
360 if (buf->fd == IBUF_FD_MARK_ON_STACK)
361 return (0);
362 return (buf->max - buf->wpos);
366 ibuf_truncate(struct ibuf *buf, size_t len)
368 if (ibuf_size(buf) >= len) {
369 buf->wpos = buf->rpos + len;
370 return (0);
372 if (buf->fd == IBUF_FD_MARK_ON_STACK) {
373 /* only allow to truncate down for stack buffers */
374 errno = ERANGE;
375 return (-1);
377 return ibuf_add_zero(buf, len - ibuf_size(buf));
380 void
381 ibuf_rewind(struct ibuf *buf)
383 buf->rpos = 0;
386 void
387 ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
389 msgbuf_enqueue(msgbuf, buf);
392 void
393 ibuf_from_buffer(struct ibuf *buf, void *data, size_t len)
395 memset(buf, 0, sizeof(*buf));
396 buf->buf = data;
397 buf->size = buf->wpos = len;
398 buf->fd = IBUF_FD_MARK_ON_STACK;
401 void
402 ibuf_from_ibuf(struct ibuf *buf, const struct ibuf *from)
404 ibuf_from_buffer(buf, ibuf_data(from), ibuf_size(from));
408 ibuf_get(struct ibuf *buf, void *data, size_t len)
410 if (ibuf_size(buf) < len) {
411 errno = EBADMSG;
412 return (-1);
415 memcpy(data, ibuf_data(buf), len);
416 buf->rpos += len;
417 return (0);
421 ibuf_get_ibuf(struct ibuf *buf, size_t len, struct ibuf *new)
423 if (ibuf_size(buf) < len) {
424 errno = EBADMSG;
425 return (-1);
428 ibuf_from_buffer(new, ibuf_data(buf), len);
429 buf->rpos += len;
430 return (0);
434 ibuf_get_h16(struct ibuf *buf, uint16_t *value)
436 return ibuf_get(buf, value, sizeof(*value));
440 ibuf_get_h32(struct ibuf *buf, uint32_t *value)
442 return ibuf_get(buf, value, sizeof(*value));
446 ibuf_get_h64(struct ibuf *buf, uint64_t *value)
448 return ibuf_get(buf, value, sizeof(*value));
452 ibuf_get_n8(struct ibuf *buf, uint8_t *value)
454 return ibuf_get(buf, value, sizeof(*value));
458 ibuf_get_n16(struct ibuf *buf, uint16_t *value)
460 int rv;
462 rv = ibuf_get(buf, value, sizeof(*value));
463 *value = be16toh(*value);
464 return (rv);
468 ibuf_get_n32(struct ibuf *buf, uint32_t *value)
470 int rv;
472 rv = ibuf_get(buf, value, sizeof(*value));
473 *value = be32toh(*value);
474 return (rv);
478 ibuf_get_n64(struct ibuf *buf, uint64_t *value)
480 int rv;
482 rv = ibuf_get(buf, value, sizeof(*value));
483 *value = be64toh(*value);
484 return (rv);
487 char *
488 ibuf_get_string(struct ibuf *buf, size_t len)
490 char *str;
492 if (ibuf_size(buf) < len) {
493 errno = EBADMSG;
494 return (NULL);
497 str = strndup(ibuf_data(buf), len);
498 if (str == NULL)
499 return (NULL);
500 buf->rpos += len;
501 return (str);
505 ibuf_skip(struct ibuf *buf, size_t len)
507 if (ibuf_size(buf) < len) {
508 errno = EBADMSG;
509 return (-1);
512 buf->rpos += len;
513 return (0);
516 void
517 ibuf_free(struct ibuf *buf)
519 if (buf == NULL)
520 return;
521 /* if buf lives on the stack abort before causing more harm */
522 if (buf->fd == IBUF_FD_MARK_ON_STACK)
523 abort();
524 if (buf->fd >= 0)
525 close(buf->fd);
526 freezero(buf->buf, buf->size);
527 free(buf);
531 ibuf_fd_avail(struct ibuf *buf)
533 return (buf->fd >= 0);
537 ibuf_fd_get(struct ibuf *buf)
539 int fd;
541 /* negative fds are internal use and equivalent to -1 */
542 if (buf->fd < 0)
543 return (-1);
544 fd = buf->fd;
545 buf->fd = -1;
546 return (fd);
549 void
550 ibuf_fd_set(struct ibuf *buf, int fd)
552 /* if buf lives on the stack abort before causing more harm */
553 if (buf->fd == IBUF_FD_MARK_ON_STACK)
554 abort();
555 if (buf->fd >= 0)
556 close(buf->fd);
557 buf->fd = -1;
558 if (fd >= 0)
559 buf->fd = fd;
562 struct msgbuf *
563 msgbuf_new(void)
565 struct msgbuf *msgbuf;
567 if ((msgbuf = calloc(1, sizeof(*msgbuf))) == NULL)
568 return (NULL);
569 msgbuf->queued = 0;
570 TAILQ_INIT(&msgbuf->bufs);
571 TAILQ_INIT(&msgbuf->rbufs);
573 return msgbuf;
576 struct msgbuf *
577 msgbuf_new_reader(size_t hdrsz,
578 struct ibuf *(*readhdr)(struct ibuf *, void *, int *), void *arg)
580 struct msgbuf *msgbuf;
581 char *buf;
583 if (hdrsz == 0 || hdrsz > IBUF_READ_SIZE / 2) {
584 errno = EINVAL;
585 return (NULL);
588 if ((buf = malloc(IBUF_READ_SIZE)) == NULL)
589 return (NULL);
591 msgbuf = msgbuf_new();
592 if (msgbuf == NULL) {
593 free(buf);
594 return (NULL);
597 msgbuf->rbuf = buf;
598 msgbuf->hdrsize = hdrsz;
599 msgbuf->readhdr = readhdr;
600 msgbuf->rarg = arg;
602 return (msgbuf);
605 void
606 msgbuf_free(struct msgbuf *msgbuf)
608 if (msgbuf == NULL)
609 return;
610 msgbuf_clear(msgbuf);
611 free(msgbuf->rbuf);
612 free(msgbuf);
615 uint32_t
616 msgbuf_queuelen(struct msgbuf *msgbuf)
618 return (msgbuf->queued);
621 void
622 msgbuf_clear(struct msgbuf *msgbuf)
624 struct ibuf *buf;
626 /* write side */
627 while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
628 msgbuf_dequeue(msgbuf, buf);
629 msgbuf->queued = 0;
631 /* read side */
632 while ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL) {
633 TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
634 ibuf_free(buf);
636 msgbuf->roff = 0;
637 ibuf_free(msgbuf->rpmsg);
638 msgbuf->rpmsg = NULL;
641 struct ibuf *
642 msgbuf_get(struct msgbuf *msgbuf)
644 struct ibuf *buf;
646 if ((buf = TAILQ_FIRST(&msgbuf->rbufs)) != NULL)
647 TAILQ_REMOVE(&msgbuf->rbufs, buf, entry);
648 return buf;
652 ibuf_write(int fd, struct msgbuf *msgbuf)
654 struct iovec iov[IOV_MAX];
655 struct ibuf *buf;
656 unsigned int i = 0;
657 ssize_t n;
659 memset(&iov, 0, sizeof(iov));
660 TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
661 if (i >= IOV_MAX)
662 break;
663 iov[i].iov_base = ibuf_data(buf);
664 iov[i].iov_len = ibuf_size(buf);
665 i++;
667 if (i == 0)
668 return (0); /* nothing queued */
670 again:
671 if ((n = writev(fd, iov, i)) == -1) {
672 if (errno == EINTR)
673 goto again;
674 if (errno == EAGAIN || errno == ENOBUFS)
675 /* lets retry later again */
676 return (0);
677 return (-1);
680 msgbuf_drain(msgbuf, n);
681 return (0);
685 msgbuf_write(int fd, struct msgbuf *msgbuf)
687 struct iovec iov[IOV_MAX];
688 struct ibuf *buf, *buf0 = NULL;
689 unsigned int i = 0;
690 ssize_t n;
691 struct msghdr msg;
692 struct cmsghdr *cmsg;
693 union {
694 struct cmsghdr hdr;
695 char buf[CMSG_SPACE(sizeof(int))];
696 } cmsgbuf;
698 memset(&iov, 0, sizeof(iov));
699 memset(&msg, 0, sizeof(msg));
700 memset(&cmsgbuf, 0, sizeof(cmsgbuf));
701 TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
702 if (i >= IOV_MAX)
703 break;
704 if (i > 0 && buf->fd != -1)
705 break;
706 iov[i].iov_base = ibuf_data(buf);
707 iov[i].iov_len = ibuf_size(buf);
708 i++;
709 if (buf->fd != -1)
710 buf0 = buf;
713 if (i == 0)
714 return (0); /* nothing queued */
716 msg.msg_iov = iov;
717 msg.msg_iovlen = i;
719 if (buf0 != NULL) {
720 msg.msg_control = (caddr_t)&cmsgbuf.buf;
721 msg.msg_controllen = sizeof(cmsgbuf.buf);
722 cmsg = CMSG_FIRSTHDR(&msg);
723 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
724 cmsg->cmsg_level = SOL_SOCKET;
725 cmsg->cmsg_type = SCM_RIGHTS;
726 *(int *)CMSG_DATA(cmsg) = buf0->fd;
729 again:
730 if ((n = sendmsg(fd, &msg, 0)) == -1) {
731 if (errno == EINTR)
732 goto again;
733 if (errno == EAGAIN || errno == ENOBUFS)
734 /* lets retry later again */
735 return (0);
736 return (-1);
740 * assumption: fd got sent if sendmsg sent anything
741 * this works because fds are passed one at a time
743 if (buf0 != NULL) {
744 close(buf0->fd);
745 buf0->fd = -1;
748 msgbuf_drain(msgbuf, n);
750 return (0);
753 static int
754 ibuf_read_process(struct msgbuf *msgbuf, int fd)
756 struct ibuf rbuf, msg;
757 ssize_t sz;
759 ibuf_from_buffer(&rbuf, msgbuf->rbuf, msgbuf->roff);
761 do {
762 if (msgbuf->rpmsg == NULL) {
763 if (ibuf_size(&rbuf) < msgbuf->hdrsize)
764 break;
765 /* get size from header */
766 ibuf_from_buffer(&msg, ibuf_data(&rbuf),
767 msgbuf->hdrsize);
768 if ((msgbuf->rpmsg = msgbuf->readhdr(&msg,
769 msgbuf->rarg, &fd)) == NULL)
770 goto fail;
773 if (ibuf_left(msgbuf->rpmsg) <= ibuf_size(&rbuf))
774 sz = ibuf_left(msgbuf->rpmsg);
775 else
776 sz = ibuf_size(&rbuf);
778 /* neither call below can fail */
779 if (ibuf_get_ibuf(&rbuf, sz, &msg) == -1 ||
780 ibuf_add_ibuf(msgbuf->rpmsg, &msg) == -1)
781 goto fail;
783 if (ibuf_left(msgbuf->rpmsg) == 0) {
784 msgbuf_read_enqueue(msgbuf, msgbuf->rpmsg);
785 msgbuf->rpmsg = NULL;
787 } while (ibuf_size(&rbuf) > 0);
789 if (ibuf_size(&rbuf) > 0)
790 memmove(msgbuf->rbuf, ibuf_data(&rbuf), ibuf_size(&rbuf));
791 msgbuf->roff = ibuf_size(&rbuf);
793 if (fd != -1)
794 close(fd);
795 return (1);
797 fail:
798 /* XXX how to properly clean up is unclear */
799 if (fd != -1)
800 close(fd);
801 return (-1);
805 ibuf_read(int fd, struct msgbuf *msgbuf)
807 struct iovec iov;
808 ssize_t n;
810 if (msgbuf->rbuf == NULL) {
811 errno = EINVAL;
812 return (-1);
815 iov.iov_base = msgbuf->rbuf + msgbuf->roff;
816 iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
818 again:
819 if ((n = readv(fd, &iov, 1)) == -1) {
820 if (errno == EINTR)
821 goto again;
822 if (errno == EAGAIN)
823 /* lets retry later again */
824 return (1);
825 return (-1);
827 if (n == 0) /* connection closed */
828 return (0);
830 msgbuf->roff += n;
831 /* new data arrived, try to process it */
832 return (ibuf_read_process(msgbuf, -1));
836 msgbuf_read(int fd, struct msgbuf *msgbuf)
838 struct msghdr msg;
839 struct cmsghdr *cmsg;
840 union {
841 struct cmsghdr hdr;
842 char buf[CMSG_SPACE(sizeof(int) * 1)];
843 } cmsgbuf;
844 struct iovec iov;
845 ssize_t n;
846 int fdpass = -1;
848 if (msgbuf->rbuf == NULL) {
849 errno = EINVAL;
850 return (-1);
853 memset(&msg, 0, sizeof(msg));
854 memset(&cmsgbuf, 0, sizeof(cmsgbuf));
856 iov.iov_base = msgbuf->rbuf + msgbuf->roff;
857 iov.iov_len = IBUF_READ_SIZE - msgbuf->roff;
858 msg.msg_iov = &iov;
859 msg.msg_iovlen = 1;
860 msg.msg_control = &cmsgbuf.buf;
861 msg.msg_controllen = sizeof(cmsgbuf.buf);
863 again:
864 if ((n = recvmsg(fd, &msg, 0)) == -1) {
865 if (errno == EINTR)
866 goto again;
867 if (errno == EMSGSIZE)
869 * Not enough fd slots: fd passing failed, retry
870 * to receive the message without fd.
871 * imsg_get_fd() will return -1 in that case.
873 goto again;
874 if (errno == EAGAIN)
875 /* lets retry later again */
876 return (1);
877 return (-1);
879 if (n == 0) /* connection closed */
880 return (0);
882 msgbuf->roff += n;
884 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
885 cmsg = CMSG_NXTHDR(&msg, cmsg)) {
886 if (cmsg->cmsg_level == SOL_SOCKET &&
887 cmsg->cmsg_type == SCM_RIGHTS) {
888 int i, j, f;
891 * We only accept one file descriptor. Due to C
892 * padding rules, our control buffer might contain
893 * more than one fd, and we must close them.
895 j = ((char *)cmsg + cmsg->cmsg_len -
896 (char *)CMSG_DATA(cmsg)) / sizeof(int);
897 for (i = 0; i < j; i++) {
898 f = ((int *)CMSG_DATA(cmsg))[i];
899 if (i == 0)
900 fdpass = f;
901 else
902 close(f);
905 /* we do not handle other ctl data level */
908 /* new data arrived, try to process it */
909 return (ibuf_read_process(msgbuf, fdpass));
912 static void
913 msgbuf_read_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
915 /* if buf lives on the stack abort before causing more harm */
916 if (buf->fd == IBUF_FD_MARK_ON_STACK)
917 abort();
918 TAILQ_INSERT_TAIL(&msgbuf->rbufs, buf, entry);
921 static void
922 msgbuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
924 /* if buf lives on the stack abort before causing more harm */
925 if (buf->fd == IBUF_FD_MARK_ON_STACK)
926 abort();
927 TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
928 msgbuf->queued++;
931 static void
932 msgbuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
934 TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
935 msgbuf->queued--;
936 ibuf_free(buf);
939 static void
940 msgbuf_drain(struct msgbuf *msgbuf, size_t n)
942 struct ibuf *buf, *next;
944 for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
945 buf = next) {
946 next = TAILQ_NEXT(buf, entry);
947 if (n >= ibuf_size(buf)) {
948 n -= ibuf_size(buf);
949 msgbuf_dequeue(msgbuf, buf);
950 } else {
951 buf->rpos += n;
952 n = 0;