summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-03-30 10:46:04 -0400
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2013-03-31 14:32:32 -0400
commitd73c3269cd3c92bb26f5e161516c587f2874c8c5 (patch)
treeac182dea6d730cb835bfad06d12d41fd3186d684
parent7a2262061252a33f6f0a009e89556fbee5b0cb41 (diff)
nss-myhostname: use _cleanup_ and split function into two
The triply nested loop is just too much. Let's split out the middle loop's body, so the whole thing is easier to read. Also modernize the style a bit, using structure initialization to avoid memset and such.
-rw-r--r--src/nss-myhostname/netlink.c256
1 files changed, 125 insertions, 131 deletions
diff --git a/src/nss-myhostname/netlink.c b/src/nss-myhostname/netlink.c
index 53c3b501be..2329f00943 100644
--- a/src/nss-myhostname/netlink.c
+++ b/src/nss-myhostname/netlink.c
@@ -35,174 +35,168 @@
#include <stdlib.h>
#include "ifconf.h"
+#include "macro.h"
+#include "util.h"
-int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
+#define SEQ 4711
+static int read_reply(int fd, struct address **list, unsigned *n_list) {
+ ssize_t bytes;
+ struct cmsghdr *cmsg;
+ struct ucred *ucred;
+ struct nlmsghdr *p;
+ uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
struct {
struct nlmsghdr hdr;
- struct rtgenmsg gen;
- } req;
- struct rtgenmsg *gen;
- int fd, r, on = 1;
- uint32_t seq = 4711;
- struct address *list = NULL;
- unsigned n_list = 0;
-
- fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
- if (fd < 0)
+ struct ifaddrmsg ifaddrmsg;
+ uint8_t payload[16*1024];
+ } resp;
+ struct iovec iov = {
+ .iov_base = &resp,
+ .iov_len = sizeof(resp),
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cred_buffer,
+ .msg_controllen = sizeof(cred_buffer),
+ .msg_flags = 0,
+ };
+
+ assert(fd >= 0);
+ assert(list);
+
+ bytes = recvmsg(fd, &msg, 0);
+ if (bytes < 0)
return -errno;
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
- r = -errno;
- goto finish;
- }
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
+ return -EIO;
- memset(&req, 0, sizeof(req));
- req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
- req.hdr.nlmsg_type = RTM_GETADDR;
- req.hdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK;
- req.hdr.nlmsg_seq = seq;
- req.hdr.nlmsg_pid = 0;
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
+ if (ucred->uid != 0 || ucred->pid != 0)
+ return 0;
- gen = NLMSG_DATA(&req.hdr);
- gen->rtgen_family = AF_UNSPEC;
+ for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
+ struct ifaddrmsg *ifaddrmsg;
+ struct rtattr *a;
+ size_t l;
+ void *local = NULL, *address = NULL;
- if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) {
- r = -errno;
- goto finish;
- }
+ if (!NLMSG_OK(p, (size_t) bytes))
+ return -EIO;
- for (;;) {
- ssize_t bytes;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct ucred *ucred;
- struct iovec iov;
- struct nlmsghdr *p;
- uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
- struct {
- struct nlmsghdr hdr;
- struct ifaddrmsg ifaddrmsg;
- uint8_t payload[16*1024];
- } resp;
-
- memset(&iov, 0, sizeof(iov));
- iov.iov_base = &resp;
- iov.iov_len = sizeof(resp);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cred_buffer;
- msg.msg_controllen = sizeof(cred_buffer);
- msg.msg_flags = 0;
-
- bytes = recvmsg(fd, &msg, 0);
- if (bytes < 0) {
- r = -errno;
- goto finish;
- }
+ if (p->nlmsg_seq != SEQ)
+ continue;
+
+ if (p->nlmsg_type == NLMSG_DONE)
+ return 1;
+
+ if (p->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *nlmsgerr;
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
- r = -EIO;
- goto finish;
+ nlmsgerr = NLMSG_DATA(p);
+ return -nlmsgerr->error;
}
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- if (ucred->uid != 0 || ucred->pid != 0)
+ if (p->nlmsg_type != RTM_NEWADDR)
continue;
- for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
- struct ifaddrmsg *ifaddrmsg;
- struct rtattr *a;
- size_t l;
- void *local = NULL, *address = NULL;
+ ifaddrmsg = NLMSG_DATA(p);
- if (!NLMSG_OK(p, (size_t) bytes)) {
- r = -EIO;
- goto finish;
- }
+ if (ifaddrmsg->ifa_family != AF_INET &&
+ ifaddrmsg->ifa_family != AF_INET6)
+ continue;
- if (p->nlmsg_seq != seq)
- continue;
+ if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
+ ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
+ continue;
- if (p->nlmsg_type == NLMSG_DONE) {
- r = 0;
- goto finish;
- }
+ if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
+ continue;
- if (p->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *nlmsgerr;
+ l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
+ a = IFA_RTA(ifaddrmsg);
- nlmsgerr = NLMSG_DATA(p);
- r = -nlmsgerr->error;
- goto finish;
- }
+ while (RTA_OK(a, l)) {
- if (p->nlmsg_type != RTM_NEWADDR)
- continue;
+ if (a->rta_type == IFA_ADDRESS)
+ address = RTA_DATA(a);
+ else if (a->rta_type == IFA_LOCAL)
+ local = RTA_DATA(a);
- ifaddrmsg = NLMSG_DATA(p);
+ a = RTA_NEXT(a, l);
+ }
- if (ifaddrmsg->ifa_family != AF_INET &&
- ifaddrmsg->ifa_family != AF_INET6)
- continue;
+ if (local)
+ address = local;
- if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
- ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
- continue;
+ if (!address)
+ continue;
- if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
- continue;
+ *list = realloc(*list, (*n_list+1) * sizeof(struct address));
+ if (!*list)
+ return -ENOMEM;
- l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
- a = IFA_RTA(ifaddrmsg);
+ (*list)[*n_list].family = ifaddrmsg->ifa_family;
+ (*list)[*n_list].scope = ifaddrmsg->ifa_scope;
+ memcpy((*list)[*n_list].address,
+ address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
+ (*list)[*n_list].ifindex = ifaddrmsg->ifa_index;
- while (RTA_OK(a, l)) {
+ (*n_list)++;
+ }
- if (a->rta_type == IFA_ADDRESS)
- address = RTA_DATA(a);
- else if (a->rta_type == IFA_LOCAL)
- local = RTA_DATA(a);
+ return 0;
+}
- a = RTA_NEXT(a, l);
- }
- if (local)
- address = local;
+int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
- if (!address)
- continue;
+ struct {
+ struct nlmsghdr hdr;
+ struct rtgenmsg gen;
+ } req = { {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+ .nlmsg_type = RTM_GETADDR,
+ .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK,
+ .nlmsg_seq = SEQ,
+ .nlmsg_pid = 0,
+ }, {
+ .rtgen_family = AF_UNSPEC,
+ }
+ };
+ int r, on = 1;
+ struct address *list = NULL;
+ unsigned n_list = 0;
+ int _cleanup_close_ fd;
- list = realloc(list, (n_list+1) * sizeof(struct address));
- if (!list) {
- r = -ENOMEM;
- goto finish;
- }
+ fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd < 0)
+ return -errno;
- list[n_list].family = ifaddrmsg->ifa_family;
- list[n_list].scope = ifaddrmsg->ifa_scope;
- memcpy(list[n_list].address, address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
- list[n_list].ifindex = ifaddrmsg->ifa_index;
+ if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0)
+ return -errno;
- n_list++;
- }
- }
+ if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0)
+ return -errno;
-finish:
- close(fd);
+ while((r = read_reply(fd, &list, &n_list)) == 0)
+ ;
- if (r < 0)
+ if (r < 0) {
free(list);
- else {
- qsort(list, n_list, sizeof(struct address), address_compare);
-
- *_list = list;
- *_n_list = n_list;
+ return r;
}
- return r;
+ assert(n_list == 0 || list);
+ qsort(list, n_list, sizeof(struct address), address_compare);
+
+ *_list = list;
+ *_n_list = n_list;
+
+ return 0;
}