xref: /netbsd-src/external/bsd/tmux/dist/compat/imsg.c (revision f844e94ef29eebc7999c12636b87f541bb86868b)
1*f844e94eSwiz /*	$OpenBSD: imsg.c,v 1.23 2023/12/12 15:47:41 claudio Exp $	*/
2698d5317Sjmmv 
3698d5317Sjmmv /*
4*f844e94eSwiz  * Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
5698d5317Sjmmv  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6698d5317Sjmmv  *
7698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
8698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
9698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
10698d5317Sjmmv  *
11698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16698d5317Sjmmv  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17698d5317Sjmmv  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18698d5317Sjmmv  */
19698d5317Sjmmv 
2099e242abSchristos #include <sys/types.h>
21698d5317Sjmmv #include <sys/socket.h>
22698d5317Sjmmv #include <sys/uio.h>
23698d5317Sjmmv 
24698d5317Sjmmv #include <errno.h>
25698d5317Sjmmv #include <stdlib.h>
26698d5317Sjmmv #include <string.h>
27698d5317Sjmmv #include <unistd.h>
28698d5317Sjmmv 
29e9a2d6faSchristos #include "compat.h"
3099e242abSchristos #include "imsg.h"
3199e242abSchristos 
32*f844e94eSwiz struct imsg_fd {
33*f844e94eSwiz 	TAILQ_ENTRY(imsg_fd)	entry;
34*f844e94eSwiz 	int			fd;
35*f844e94eSwiz };
36*f844e94eSwiz 
3799e242abSchristos int	 imsg_fd_overhead = 0;
38698d5317Sjmmv 
39*f844e94eSwiz static int	 imsg_dequeue_fd(struct imsgbuf *);
40698d5317Sjmmv 
41698d5317Sjmmv void
imsg_init(struct imsgbuf * imsgbuf,int fd)42*f844e94eSwiz imsg_init(struct imsgbuf *imsgbuf, int fd)
43698d5317Sjmmv {
44*f844e94eSwiz 	msgbuf_init(&imsgbuf->w);
45*f844e94eSwiz 	memset(&imsgbuf->r, 0, sizeof(imsgbuf->r));
46*f844e94eSwiz 	imsgbuf->fd = fd;
47*f844e94eSwiz 	imsgbuf->w.fd = fd;
48*f844e94eSwiz 	imsgbuf->pid = getpid();
49*f844e94eSwiz 	TAILQ_INIT(&imsgbuf->fds);
50698d5317Sjmmv }
51698d5317Sjmmv 
52698d5317Sjmmv ssize_t
imsg_read(struct imsgbuf * imsgbuf)53*f844e94eSwiz imsg_read(struct imsgbuf *imsgbuf)
54698d5317Sjmmv {
55698d5317Sjmmv 	struct msghdr		 msg;
56698d5317Sjmmv 	struct cmsghdr		*cmsg;
57698d5317Sjmmv 	union {
58698d5317Sjmmv 		struct cmsghdr hdr;
5999e242abSchristos 		char	buf[CMSG_SPACE(sizeof(int) * 1)];
60698d5317Sjmmv 	} cmsgbuf;
61698d5317Sjmmv 	struct iovec		 iov;
6299e242abSchristos 	ssize_t			 n = -1;
63698d5317Sjmmv 	int			 fd;
64698d5317Sjmmv 	struct imsg_fd		*ifd;
65698d5317Sjmmv 
6699e242abSchristos 	memset(&msg, 0, sizeof(msg));
6799e242abSchristos 	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
68698d5317Sjmmv 
69*f844e94eSwiz 	iov.iov_base = imsgbuf->r.buf + imsgbuf->r.wpos;
70*f844e94eSwiz 	iov.iov_len = sizeof(imsgbuf->r.buf) - imsgbuf->r.wpos;
71698d5317Sjmmv 	msg.msg_iov = &iov;
72698d5317Sjmmv 	msg.msg_iovlen = 1;
73698d5317Sjmmv 	msg.msg_control = &cmsgbuf.buf;
749692a535Sjoerg 	msg.msg_controllen = CMSG_SPACE(sizeof(int) * 16);
75698d5317Sjmmv 
7699e242abSchristos 	if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
7799e242abSchristos 		return (-1);
7899e242abSchristos 
7999e242abSchristos again:
80e9a2d6faSchristos 	if (getdtablecount() + imsg_fd_overhead +
81e9a2d6faSchristos 	    (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
82e9a2d6faSchristos 	    >= getdtablesize()) {
8399e242abSchristos 		errno = EAGAIN;
8499e242abSchristos 		free(ifd);
85698d5317Sjmmv 		return (-1);
86698d5317Sjmmv 	}
8799e242abSchristos 
88*f844e94eSwiz 	if ((n = recvmsg(imsgbuf->fd, &msg, 0)) == -1) {
89e9a2d6faSchristos 		if (errno == EINTR)
9099e242abSchristos 			goto again;
91e9a2d6faSchristos 		goto fail;
92698d5317Sjmmv 	}
93698d5317Sjmmv 
94*f844e94eSwiz 	imsgbuf->r.wpos += n;
95698d5317Sjmmv 
96698d5317Sjmmv 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
97698d5317Sjmmv 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
98698d5317Sjmmv 		if (cmsg->cmsg_level == SOL_SOCKET &&
99698d5317Sjmmv 		    cmsg->cmsg_type == SCM_RIGHTS) {
10099e242abSchristos 			int i;
10199e242abSchristos 			int j;
10299e242abSchristos 
10399e242abSchristos 			/*
10499e242abSchristos 			 * We only accept one file descriptor.  Due to C
10599e242abSchristos 			 * padding rules, our control buffer might contain
10699e242abSchristos 			 * more than one fd, and we must close them.
10799e242abSchristos 			 */
10899e242abSchristos 			j = ((char *)cmsg + cmsg->cmsg_len -
10999e242abSchristos 			    (char *)CMSG_DATA(cmsg)) / sizeof(int);
11099e242abSchristos 			for (i = 0; i < j; i++) {
11199e242abSchristos 				fd = ((int *)CMSG_DATA(cmsg))[i];
11299e242abSchristos 				if (ifd != NULL) {
113698d5317Sjmmv 					ifd->fd = fd;
114*f844e94eSwiz 					TAILQ_INSERT_TAIL(&imsgbuf->fds, ifd,
11599e242abSchristos 					    entry);
11699e242abSchristos 					ifd = NULL;
11799e242abSchristos 				} else
11899e242abSchristos 					close(fd);
11999e242abSchristos 			}
120698d5317Sjmmv 		}
121698d5317Sjmmv 		/* we do not handle other ctl data level */
122698d5317Sjmmv 	}
123698d5317Sjmmv 
12499e242abSchristos fail:
12599e242abSchristos 	free(ifd);
126698d5317Sjmmv 	return (n);
127698d5317Sjmmv }
128698d5317Sjmmv 
129698d5317Sjmmv ssize_t
imsg_get(struct imsgbuf * imsgbuf,struct imsg * imsg)130*f844e94eSwiz imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg)
131698d5317Sjmmv {
132*f844e94eSwiz 	struct imsg		 m;
133698d5317Sjmmv 	size_t			 av, left, datalen;
134698d5317Sjmmv 
135*f844e94eSwiz 	av = imsgbuf->r.wpos;
136698d5317Sjmmv 
137698d5317Sjmmv 	if (IMSG_HEADER_SIZE > av)
138698d5317Sjmmv 		return (0);
139698d5317Sjmmv 
140*f844e94eSwiz 	memcpy(&m.hdr, imsgbuf->r.buf, sizeof(m.hdr));
141*f844e94eSwiz 	if (m.hdr.len < IMSG_HEADER_SIZE ||
142*f844e94eSwiz 	    m.hdr.len > MAX_IMSGSIZE) {
143698d5317Sjmmv 		errno = ERANGE;
144698d5317Sjmmv 		return (-1);
145698d5317Sjmmv 	}
146*f844e94eSwiz 	if (m.hdr.len > av)
147698d5317Sjmmv 		return (0);
148*f844e94eSwiz 
149*f844e94eSwiz 	m.fd = -1;
150*f844e94eSwiz 	m.buf = NULL;
151*f844e94eSwiz 	m.data = NULL;
152*f844e94eSwiz 
153*f844e94eSwiz 	datalen = m.hdr.len - IMSG_HEADER_SIZE;
154*f844e94eSwiz 	imsgbuf->r.rptr = imsgbuf->r.buf + IMSG_HEADER_SIZE;
155*f844e94eSwiz 	if (datalen != 0) {
156*f844e94eSwiz 		if ((m.buf = ibuf_open(datalen)) == NULL)
157698d5317Sjmmv 			return (-1);
158*f844e94eSwiz 		if (ibuf_add(m.buf, imsgbuf->r.rptr, datalen) == -1) {
159*f844e94eSwiz 			/* this should never fail */
160*f844e94eSwiz 			ibuf_free(m.buf);
161*f844e94eSwiz 			return (-1);
162*f844e94eSwiz 		}
163*f844e94eSwiz 		m.data = ibuf_data(m.buf);
164*f844e94eSwiz 	}
165698d5317Sjmmv 
166*f844e94eSwiz 	if (m.hdr.flags & IMSGF_HASFD)
167*f844e94eSwiz 		m.fd = imsg_dequeue_fd(imsgbuf);
168698d5317Sjmmv 
169*f844e94eSwiz 	if (m.hdr.len < av) {
170*f844e94eSwiz 		left = av - m.hdr.len;
171*f844e94eSwiz 		memmove(&imsgbuf->r.buf, imsgbuf->r.buf + m.hdr.len, left);
172*f844e94eSwiz 		imsgbuf->r.wpos = left;
173698d5317Sjmmv 	} else
174*f844e94eSwiz 		imsgbuf->r.wpos = 0;
175698d5317Sjmmv 
176*f844e94eSwiz 	*imsg = m;
177698d5317Sjmmv 	return (datalen + IMSG_HEADER_SIZE);
178698d5317Sjmmv }
179698d5317Sjmmv 
180698d5317Sjmmv int
imsg_get_ibuf(struct imsg * imsg,struct ibuf * ibuf)181*f844e94eSwiz imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf)
182*f844e94eSwiz {
183*f844e94eSwiz 	if (imsg->buf == NULL) {
184*f844e94eSwiz 		errno = EBADMSG;
185*f844e94eSwiz 		return (-1);
186*f844e94eSwiz 	}
187*f844e94eSwiz 	return ibuf_get_ibuf(imsg->buf, ibuf_size(imsg->buf), ibuf);
188*f844e94eSwiz }
189*f844e94eSwiz 
190*f844e94eSwiz int
imsg_get_data(struct imsg * imsg,void * data,size_t len)191*f844e94eSwiz imsg_get_data(struct imsg *imsg, void *data, size_t len)
192*f844e94eSwiz {
193*f844e94eSwiz 	if (len == 0) {
194*f844e94eSwiz 		errno = EINVAL;
195*f844e94eSwiz 		return (-1);
196*f844e94eSwiz 	}
197*f844e94eSwiz 	if (imsg->buf == NULL || ibuf_size(imsg->buf) != len) {
198*f844e94eSwiz 		errno = EBADMSG;
199*f844e94eSwiz 		return (-1);
200*f844e94eSwiz 	}
201*f844e94eSwiz 	return ibuf_get(imsg->buf, data, len);
202*f844e94eSwiz }
203*f844e94eSwiz 
204*f844e94eSwiz int
imsg_get_fd(struct imsg * imsg)205*f844e94eSwiz imsg_get_fd(struct imsg *imsg)
206*f844e94eSwiz {
207*f844e94eSwiz 	int fd = imsg->fd;
208*f844e94eSwiz 
209*f844e94eSwiz 	imsg->fd = -1;
210*f844e94eSwiz 	return fd;
211*f844e94eSwiz }
212*f844e94eSwiz 
213*f844e94eSwiz uint32_t
imsg_get_id(struct imsg * imsg)214*f844e94eSwiz imsg_get_id(struct imsg *imsg)
215*f844e94eSwiz {
216*f844e94eSwiz 	return (imsg->hdr.peerid);
217*f844e94eSwiz }
218*f844e94eSwiz 
219*f844e94eSwiz size_t
imsg_get_len(struct imsg * imsg)220*f844e94eSwiz imsg_get_len(struct imsg *imsg)
221*f844e94eSwiz {
222*f844e94eSwiz 	if (imsg->buf == NULL)
223*f844e94eSwiz 		return 0;
224*f844e94eSwiz 	return ibuf_size(imsg->buf);
225*f844e94eSwiz }
226*f844e94eSwiz 
227*f844e94eSwiz pid_t
imsg_get_pid(struct imsg * imsg)228*f844e94eSwiz imsg_get_pid(struct imsg *imsg)
229*f844e94eSwiz {
230*f844e94eSwiz 	return (imsg->hdr.pid);
231*f844e94eSwiz }
232*f844e94eSwiz 
233*f844e94eSwiz uint32_t
imsg_get_type(struct imsg * imsg)234*f844e94eSwiz imsg_get_type(struct imsg *imsg)
235*f844e94eSwiz {
236*f844e94eSwiz 	return (imsg->hdr.type);
237*f844e94eSwiz }
238*f844e94eSwiz 
239*f844e94eSwiz int
imsg_compose(struct imsgbuf * imsgbuf,uint32_t type,uint32_t id,pid_t pid,int fd,const void * data,size_t datalen)240*f844e94eSwiz imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
241*f844e94eSwiz     int fd, const void *data, size_t datalen)
242698d5317Sjmmv {
243698d5317Sjmmv 	struct ibuf	*wbuf;
244698d5317Sjmmv 
245*f844e94eSwiz 	if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
246698d5317Sjmmv 		return (-1);
247698d5317Sjmmv 
248698d5317Sjmmv 	if (imsg_add(wbuf, data, datalen) == -1)
249698d5317Sjmmv 		return (-1);
250698d5317Sjmmv 
251*f844e94eSwiz 	ibuf_fd_set(wbuf, fd);
252*f844e94eSwiz 	imsg_close(imsgbuf, wbuf);
253698d5317Sjmmv 
254698d5317Sjmmv 	return (1);
255698d5317Sjmmv }
256698d5317Sjmmv 
257698d5317Sjmmv int
imsg_composev(struct imsgbuf * imsgbuf,uint32_t type,uint32_t id,pid_t pid,int fd,const struct iovec * iov,int iovcnt)258*f844e94eSwiz imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
259e9a2d6faSchristos     int fd, const struct iovec *iov, int iovcnt)
260698d5317Sjmmv {
261698d5317Sjmmv 	struct ibuf	*wbuf;
262*f844e94eSwiz 	int		 i;
263*f844e94eSwiz 	size_t		 datalen = 0;
264698d5317Sjmmv 
265698d5317Sjmmv 	for (i = 0; i < iovcnt; i++)
266698d5317Sjmmv 		datalen += iov[i].iov_len;
267698d5317Sjmmv 
268*f844e94eSwiz 	if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL)
269698d5317Sjmmv 		return (-1);
270698d5317Sjmmv 
271698d5317Sjmmv 	for (i = 0; i < iovcnt; i++)
272698d5317Sjmmv 		if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
273698d5317Sjmmv 			return (-1);
274698d5317Sjmmv 
275*f844e94eSwiz 	ibuf_fd_set(wbuf, fd);
276*f844e94eSwiz 	imsg_close(imsgbuf, wbuf);
277698d5317Sjmmv 
278698d5317Sjmmv 	return (1);
279698d5317Sjmmv }
280698d5317Sjmmv 
281*f844e94eSwiz /*
282*f844e94eSwiz  * Enqueue imsg with payload from ibuf buf. fd passing is not possible
283*f844e94eSwiz  * with this function.
284*f844e94eSwiz  */
285*f844e94eSwiz int
imsg_compose_ibuf(struct imsgbuf * imsgbuf,uint32_t type,uint32_t id,pid_t pid,struct ibuf * buf)286*f844e94eSwiz imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id,
287*f844e94eSwiz     pid_t pid, struct ibuf *buf)
288*f844e94eSwiz {
289*f844e94eSwiz 	struct ibuf	*hdrbuf = NULL;
290*f844e94eSwiz 	struct imsg_hdr	 hdr;
291*f844e94eSwiz 	int save_errno;
292*f844e94eSwiz 
293*f844e94eSwiz 	if (ibuf_size(buf) + IMSG_HEADER_SIZE > MAX_IMSGSIZE) {
294*f844e94eSwiz 		errno = ERANGE;
295*f844e94eSwiz 		goto fail;
296*f844e94eSwiz 	}
297*f844e94eSwiz 
298*f844e94eSwiz 	hdr.type = type;
299*f844e94eSwiz 	hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
300*f844e94eSwiz 	hdr.flags = 0;
301*f844e94eSwiz 	hdr.peerid = id;
302*f844e94eSwiz 	if ((hdr.pid = pid) == 0)
303*f844e94eSwiz 		hdr.pid = imsgbuf->pid;
304*f844e94eSwiz 
305*f844e94eSwiz 	if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
306*f844e94eSwiz 		goto fail;
307*f844e94eSwiz 	if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
308*f844e94eSwiz 		goto fail;
309*f844e94eSwiz 
310*f844e94eSwiz 	ibuf_close(&imsgbuf->w, hdrbuf);
311*f844e94eSwiz 	ibuf_close(&imsgbuf->w, buf);
312*f844e94eSwiz 	return (1);
313*f844e94eSwiz 
314*f844e94eSwiz  fail:
315*f844e94eSwiz 	save_errno = errno;
316*f844e94eSwiz 	ibuf_free(buf);
317*f844e94eSwiz 	ibuf_free(hdrbuf);
318*f844e94eSwiz 	errno = save_errno;
319*f844e94eSwiz 	return (-1);
320*f844e94eSwiz }
321*f844e94eSwiz 
322*f844e94eSwiz /*
323*f844e94eSwiz  * Forward imsg to another channel. Any attached fd is closed.
324*f844e94eSwiz  */
325*f844e94eSwiz int
imsg_forward(struct imsgbuf * imsgbuf,struct imsg * msg)326*f844e94eSwiz imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
327*f844e94eSwiz {
328*f844e94eSwiz 	struct ibuf	*wbuf;
329*f844e94eSwiz 	size_t		 len = 0;
330*f844e94eSwiz 
331*f844e94eSwiz 	if (msg->fd != -1) {
332*f844e94eSwiz 		close(msg->fd);
333*f844e94eSwiz 		msg->fd = -1;
334*f844e94eSwiz 	}
335*f844e94eSwiz 
336*f844e94eSwiz 	if (msg->buf != NULL) {
337*f844e94eSwiz 		ibuf_rewind(msg->buf);
338*f844e94eSwiz 		len = ibuf_size(msg->buf);
339*f844e94eSwiz 	}
340*f844e94eSwiz 
341*f844e94eSwiz 	if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
342*f844e94eSwiz 	    msg->hdr.pid, len)) == NULL)
343*f844e94eSwiz 		return (-1);
344*f844e94eSwiz 
345*f844e94eSwiz 	if (msg->buf != NULL) {
346*f844e94eSwiz 		if (ibuf_add_buf(wbuf, msg->buf) == -1) {
347*f844e94eSwiz 			ibuf_free(wbuf);
348*f844e94eSwiz 			return (-1);
349*f844e94eSwiz 		}
350*f844e94eSwiz 	}
351*f844e94eSwiz 
352*f844e94eSwiz 	imsg_close(imsgbuf, wbuf);
353*f844e94eSwiz 	return (1);
354*f844e94eSwiz }
355*f844e94eSwiz 
356698d5317Sjmmv struct ibuf *
imsg_create(struct imsgbuf * imsgbuf,uint32_t type,uint32_t id,pid_t pid,size_t datalen)357*f844e94eSwiz imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
358*f844e94eSwiz     size_t datalen)
359698d5317Sjmmv {
360698d5317Sjmmv 	struct ibuf	*wbuf;
361698d5317Sjmmv 	struct imsg_hdr	 hdr;
362698d5317Sjmmv 
363698d5317Sjmmv 	datalen += IMSG_HEADER_SIZE;
364698d5317Sjmmv 	if (datalen > MAX_IMSGSIZE) {
365698d5317Sjmmv 		errno = ERANGE;
366698d5317Sjmmv 		return (NULL);
367698d5317Sjmmv 	}
368698d5317Sjmmv 
369698d5317Sjmmv 	hdr.type = type;
370698d5317Sjmmv 	hdr.flags = 0;
371*f844e94eSwiz 	hdr.peerid = id;
372698d5317Sjmmv 	if ((hdr.pid = pid) == 0)
373*f844e94eSwiz 		hdr.pid = imsgbuf->pid;
374698d5317Sjmmv 	if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
375698d5317Sjmmv 		return (NULL);
376698d5317Sjmmv 	}
377698d5317Sjmmv 	if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
378698d5317Sjmmv 		return (NULL);
379698d5317Sjmmv 
380698d5317Sjmmv 	return (wbuf);
381698d5317Sjmmv }
382698d5317Sjmmv 
383698d5317Sjmmv int
imsg_add(struct ibuf * msg,const void * data,size_t datalen)384*f844e94eSwiz imsg_add(struct ibuf *msg, const void *data, size_t datalen)
385698d5317Sjmmv {
386698d5317Sjmmv 	if (datalen)
387698d5317Sjmmv 		if (ibuf_add(msg, data, datalen) == -1) {
388698d5317Sjmmv 			ibuf_free(msg);
389698d5317Sjmmv 			return (-1);
390698d5317Sjmmv 		}
391698d5317Sjmmv 	return (datalen);
392698d5317Sjmmv }
393698d5317Sjmmv 
394698d5317Sjmmv void
imsg_close(struct imsgbuf * imsgbuf,struct ibuf * msg)395*f844e94eSwiz imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg)
396698d5317Sjmmv {
397698d5317Sjmmv 	struct imsg_hdr	*hdr;
398698d5317Sjmmv 
399698d5317Sjmmv 	hdr = (struct imsg_hdr *)msg->buf;
400698d5317Sjmmv 
401698d5317Sjmmv 	hdr->flags &= ~IMSGF_HASFD;
402*f844e94eSwiz 	if (ibuf_fd_avail(msg))
403698d5317Sjmmv 		hdr->flags |= IMSGF_HASFD;
404*f844e94eSwiz 	hdr->len = ibuf_size(msg);
405698d5317Sjmmv 
406*f844e94eSwiz 	ibuf_close(&imsgbuf->w, msg);
407698d5317Sjmmv }
408698d5317Sjmmv 
409698d5317Sjmmv void
imsg_free(struct imsg * imsg)410698d5317Sjmmv imsg_free(struct imsg *imsg)
411698d5317Sjmmv {
412*f844e94eSwiz 	ibuf_free(imsg->buf);
413698d5317Sjmmv }
414698d5317Sjmmv 
415c7e17de0Schristos static int
imsg_dequeue_fd(struct imsgbuf * imsgbuf)416*f844e94eSwiz imsg_dequeue_fd(struct imsgbuf *imsgbuf)
417698d5317Sjmmv {
418698d5317Sjmmv 	int		 fd;
419698d5317Sjmmv 	struct imsg_fd	*ifd;
420698d5317Sjmmv 
421*f844e94eSwiz 	if ((ifd = TAILQ_FIRST(&imsgbuf->fds)) == NULL)
422698d5317Sjmmv 		return (-1);
423698d5317Sjmmv 
424698d5317Sjmmv 	fd = ifd->fd;
425*f844e94eSwiz 	TAILQ_REMOVE(&imsgbuf->fds, ifd, entry);
426698d5317Sjmmv 	free(ifd);
427698d5317Sjmmv 
428698d5317Sjmmv 	return (fd);
429698d5317Sjmmv }
430698d5317Sjmmv 
431698d5317Sjmmv int
imsg_flush(struct imsgbuf * imsgbuf)432*f844e94eSwiz imsg_flush(struct imsgbuf *imsgbuf)
433698d5317Sjmmv {
434*f844e94eSwiz 	while (imsgbuf->w.queued)
435*f844e94eSwiz 		if (msgbuf_write(&imsgbuf->w) <= 0)
436698d5317Sjmmv 			return (-1);
437698d5317Sjmmv 	return (0);
438698d5317Sjmmv }
439698d5317Sjmmv 
440698d5317Sjmmv void
imsg_clear(struct imsgbuf * imsgbuf)441*f844e94eSwiz imsg_clear(struct imsgbuf *imsgbuf)
442698d5317Sjmmv {
443698d5317Sjmmv 	int	fd;
444698d5317Sjmmv 
445*f844e94eSwiz 	msgbuf_clear(&imsgbuf->w);
446*f844e94eSwiz 	while ((fd = imsg_dequeue_fd(imsgbuf)) != -1)
447698d5317Sjmmv 		close(fd);
448698d5317Sjmmv }
449