From: Stephen Hemminger Date: Sat, 26 Jan 2008 19:09:42 +0000 (-0800) Subject: poll for errors after rtnl_send X-Git-Tag: v2.6.25~43 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=54bb35c69cec6c730a4ac95530a1d2ca6670f73b;p=thirdparty%2Fiproute2.git poll for errors after rtnl_send This fixes the problem where a bulk operation (like ip flush) is performed as non-root user. The kernel will only send a response if there is an error, so check for it. --- diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 7876c190b..a4e91cf7c 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -114,11 +114,39 @@ int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) int rtnl_send(struct rtnl_handle *rth, const char *buf, int len) { struct sockaddr_nl nladdr; + struct nlmsghdr *h; + int status; + char resp[1024]; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; - return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); + status = sendto(rth->fd, buf, len, 0, + (struct sockaddr*)&nladdr, sizeof(nladdr)); + if (status < 0) + return status; + + /* Check for errors */ + status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT); + if (status < 0) { + if (errno == EAGAIN) + return 0; + return -1; + } + + for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); + h = NLMSG_NEXT(h, status)) { + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) + fprintf(stderr, "ERROR truncated\n"); + else + errno = -err->error; + } + return -1; + } + + return 0; } int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)