|
|
@ -1,4 +1,4 @@ |
|
|
|
/* $OpenBSD: imsg.c,v 1.12 2007/03/19 10:03:25 henning Exp $ */ |
|
|
|
/* $OpenBSD: imsg.c,v 1.13 2009/06/06 18:14:25 pyr Exp $ */ |
|
|
|
|
|
|
|
/* |
|
|
|
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> |
|
|
@ -11,19 +11,22 @@ |
|
|
|
* 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 MIND, 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. |
|
|
|
* 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/types.h> |
|
|
|
#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 "ntpd.h" |
|
|
|
#include "imsg.h" |
|
|
|
|
|
|
|
void |
|
|
|
imsg_init(struct imsgbuf *ibuf, int fd) |
|
|
@ -33,17 +36,34 @@ imsg_init(struct imsgbuf *ibuf, int fd) |
|
|
|
ibuf->fd = fd; |
|
|
|
ibuf->w.fd = fd; |
|
|
|
ibuf->pid = getpid(); |
|
|
|
TAILQ_INIT(&ibuf->fds); |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
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 = read(ibuf->fd, ibuf->r.buf + ibuf->r.wpos, |
|
|
|
sizeof(ibuf->r.buf) - ibuf->r.wpos)) == -1) { |
|
|
|
if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { |
|
|
|
if (errno != EINTR && errno != EAGAIN) { |
|
|
|
log_warn("imsg_read: pipe read error"); |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
return (-2); |
|
|
@ -51,10 +71,25 @@ imsg_read(struct imsgbuf *ibuf) |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
ssize_t |
|
|
|
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) |
|
|
|
{ |
|
|
|
size_t av, left, datalen; |
|
|
@ -67,8 +102,7 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) |
|
|
|
memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); |
|
|
|
if (imsg->hdr.len < IMSG_HEADER_SIZE || |
|
|
|
imsg->hdr.len > MAX_IMSGSIZE) { |
|
|
|
log_warnx("imsg_get: imsg hdr len %u out of bounds, type=%u", |
|
|
|
imsg->hdr.len, imsg->hdr.type); |
|
|
|
errno = ERANGE; |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
if (imsg->hdr.len > av) |
|
|
@ -76,7 +110,6 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) |
|
|
|
datalen = imsg->hdr.len - IMSG_HEADER_SIZE; |
|
|
|
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; |
|
|
|
if ((imsg->data = malloc(datalen)) == NULL) { |
|
|
|
log_warn("imsg_get"); |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
memcpy(imsg->data, ibuf->r.rptr, datalen); |
|
|
@ -92,11 +125,10 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
imsg_compose(struct imsgbuf *ibuf, enum imsg_type type, u_int32_t peerid, |
|
|
|
pid_t pid, void *data, u_int16_t datalen) |
|
|
|
imsg_compose(struct imsgbuf *ibuf, u_int16_t type, u_int32_t peerid, |
|
|
|
pid_t pid, int fd, void *data, u_int16_t datalen) |
|
|
|
{ |
|
|
|
struct buf *wbuf; |
|
|
|
int n; |
|
|
|
|
|
|
|
if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) |
|
|
|
return (-1); |
|
|
@ -104,32 +136,56 @@ imsg_compose(struct imsgbuf *ibuf, enum imsg_type type, u_int32_t peerid, |
|
|
|
if (imsg_add(wbuf, data, datalen) == -1) |
|
|
|
return (-1); |
|
|
|
|
|
|
|
if ((n = imsg_close(ibuf, wbuf)) < 0) |
|
|
|
wbuf->fd = fd; |
|
|
|
|
|
|
|
imsg_close(ibuf, wbuf); |
|
|
|
|
|
|
|
return (1); |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
imsg_composev(struct imsgbuf *ibuf, u_int16_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); |
|
|
|
|
|
|
|
return (n); |
|
|
|
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, enum imsg_type type, u_int32_t peerid, |
|
|
|
imsg_create(struct imsgbuf *ibuf, u_int16_t type, u_int32_t peerid, |
|
|
|
pid_t pid, u_int16_t datalen) |
|
|
|
{ |
|
|
|
struct buf *wbuf; |
|
|
|
struct imsg_hdr hdr; |
|
|
|
|
|
|
|
if (datalen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { |
|
|
|
log_warnx("imsg_create: len %u > MAX_IMSGSIZE; " |
|
|
|
"type %u peerid %lu", datalen + IMSG_HEADER_SIZE, |
|
|
|
type, peerid); |
|
|
|
datalen += IMSG_HEADER_SIZE; |
|
|
|
if (datalen > MAX_IMSGSIZE) { |
|
|
|
errno = ERANGE; |
|
|
|
return (NULL); |
|
|
|
} |
|
|
|
|
|
|
|
hdr.len = datalen + IMSG_HEADER_SIZE; |
|
|
|
hdr.type = type; |
|
|
|
hdr.peerid = peerid; |
|
|
|
hdr.pid = pid; |
|
|
|
if ((wbuf = buf_open(hdr.len)) == NULL) { |
|
|
|
log_warn("imsg_create: buf_open"); |
|
|
|
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) |
|
|
@ -143,24 +199,20 @@ imsg_add(struct buf *msg, void *data, u_int16_t datalen) |
|
|
|
{ |
|
|
|
if (datalen) |
|
|
|
if (buf_add(msg, data, datalen) == -1) { |
|
|
|
log_warnx("imsg_add: buf_add error"); |
|
|
|
buf_free(msg); |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
return (datalen); |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
void |
|
|
|
imsg_close(struct imsgbuf *ibuf, struct buf *msg) |
|
|
|
{ |
|
|
|
int n; |
|
|
|
struct imsg_hdr *hdr; |
|
|
|
|
|
|
|
if ((n = buf_close(&ibuf->w, msg)) < 0) { |
|
|
|
log_warnx("imsg_close: buf_close error"); |
|
|
|
buf_free(msg); |
|
|
|
return (-1); |
|
|
|
} |
|
|
|
return (n); |
|
|
|
hdr = (struct imsg_hdr *)msg->buf; |
|
|
|
hdr->len = (u_int16_t)msg->wpos; |
|
|
|
buf_close(&ibuf->w, msg); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
@ -168,3 +220,35 @@ 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) |
|
|
|
{ |
|
|
|
while (ibuf->w.queued) |
|
|
|
msgbuf_clear(&ibuf->w); |
|
|
|
} |