vtysh: receive file descriptors from daemons

The other half of yielding back a file descriptor from a daemon to
vtysh.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
David Lamparter 2019-12-04 00:17:50 +01:00 committed by David Lamparter
parent e960eedd98
commit 12d25fa69a

View File

@ -182,6 +182,53 @@ static void vclient_close(struct vtysh_client *vclient)
} }
} }
static ssize_t vtysh_client_receive(struct vtysh_client *vclient,
char *buf, size_t bufsz, int *pass_fd)
{
struct iovec iov[1] = {
{
.iov_base = buf,
.iov_len = bufsz,
},
};
union {
uint8_t buf[CMSG_SPACE(sizeof(int))];
struct cmsghdr align;
} u;
struct msghdr mh = {
.msg_iov = iov,
.msg_iovlen = array_size(iov),
.msg_control = u.buf,
.msg_controllen = sizeof(u.buf),
};
struct cmsghdr *cmh = CMSG_FIRSTHDR(&mh);
ssize_t ret;
cmh->cmsg_level = SOL_SOCKET;
cmh->cmsg_type = SCM_RIGHTS;
cmh->cmsg_len = CMSG_LEN(sizeof(int));
memset(CMSG_DATA(cmh), -1, sizeof(int));
do {
ret = recvmsg(vclient->fd, &mh, 0);
if (ret < 0 && (errno == EINTR || errno == EAGAIN))
continue;
} while (false);
if (cmh->cmsg_len == CMSG_LEN(sizeof(int))) {
int fd;
memcpy(&fd, CMSG_DATA(cmh), sizeof(int));
if (fd != -1) {
if (pass_fd)
*pass_fd = fd;
else
close(fd);
}
}
return ret;
}
/* /*
* Send a CLI command to a client and read the response. * Send a CLI command to a client and read the response.
* *
@ -205,7 +252,8 @@ static void vclient_close(struct vtysh_client *vclient)
* a status code * a status code
*/ */
static int vtysh_client_run(struct vtysh_client *vclient, const char *line, static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
void (*callback)(void *, const char *), void *cbarg) void (*callback)(void *, const char *), void *cbarg,
int *pass_fd)
{ {
int ret; int ret;
char stackbuf[4096]; char stackbuf[4096];
@ -239,8 +287,11 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line,
bufvalid = buf; bufvalid = buf;
do { do {
ssize_t nread = ssize_t nread;
read(vclient->fd, bufvalid, buf + bufsz - bufvalid - 1);
nread = vtysh_client_receive(vclient, bufvalid,
buf + bufsz - bufvalid - 1,
pass_fd);
if (nread < 0 && (errno == EINTR || errno == EAGAIN)) if (nread < 0 && (errno == EINTR || errno == EAGAIN))
continue; continue;
@ -382,7 +433,7 @@ static int vtysh_client_run_all(struct vtysh_client *head_client,
int correct_instance = 0, wrong_instance = 0; int correct_instance = 0, wrong_instance = 0;
for (client = head_client; client; client = client->next) { for (client = head_client; client; client = client->next) {
rc = vtysh_client_run(client, line, callback, cbarg); rc = vtysh_client_run(client, line, callback, cbarg, NULL);
if (rc == CMD_NOT_MY_INSTANCE) { if (rc == CMD_NOT_MY_INSTANCE) {
wrong_instance++; wrong_instance++;
continue; continue;