Fix changes to interface list during getifaddrs calls.

This commit is contained in:
Ulrich Drepper 2010-04-03 20:36:59 -07:00
parent 3ed8e24122
commit b8b14c4cc3
2 changed files with 53 additions and 12 deletions

View File

@ -1,3 +1,13 @@
2010-04-03 Ulrich Drepper <drepper@redhat.com>
[BZ #11387]
* sysdeps/unix/sysv/linux/ifaddrs.c (map_newlin): Don't abort on
unknown interface, return -1.
(getifaddrs_internal): Rename from getifaddrs. Handle errors in
map_newlink be returning -EAGAIN.
(getifaddrs): If -EAGAIN is returned from getifaddrs_internal try
again.
2010-03-25 Ryan S. Arnold <rsa@us.ibm.com> 2010-03-25 Ryan S. Arnold <rsa@us.ibm.com>
* sysdeps/unix/sysv/linux/getsysstats.c (next_line): Remove * sysdeps/unix/sysv/linux/getsysstats.c (next_line): Remove

View File

@ -1,5 +1,5 @@
/* getifaddrs -- get names and addresses of all network interfaces /* getifaddrs -- get names and addresses of all network interfaces
Copyright (C) 2003-2008, 2009 Free Software Foundation, Inc. Copyright (C) 2003-2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -315,17 +315,19 @@ map_newlink (int index, struct ifaddrs_storage *ifas, int *map, int max)
else if (map[i] == index) else if (map[i] == index)
return i; return i;
} }
/* This should never be reached. If this will be reached, we have
a very big problem. */ /* This means interfaces changed inbetween the reading of the
abort (); RTM_GETLINK and RTM_GETADDR information. We have to repeat
everything. */
return -1;
} }
/* Create a linked list of `struct ifaddrs' structures, one for each /* Create a linked list of `struct ifaddrs' structures, one for each
network interface on the host machine. If successful, store the network interface on the host machine. If successful, store the
list in *IFAP and return 0. On errors, return -1 and set `errno'. */ list in *IFAP and return 0. On errors, return -1 and set `errno'. */
int static int
getifaddrs (struct ifaddrs **ifap) getifaddrs_internal (struct ifaddrs **ifap)
{ {
struct netlink_handle nh = { 0, 0, 0, NULL, NULL }; struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
struct netlink_res *nlp; struct netlink_res *nlp;
@ -481,6 +483,13 @@ getifaddrs (struct ifaddrs **ifap)
kernel. */ kernel. */
ifa_index = map_newlink (ifim->ifi_index - 1, ifas, ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
map_newlink_data, newlink); map_newlink_data, newlink);
if (__builtin_expect (ifa_index == -1, 0))
{
try_again:
result = -EAGAIN;
free (ifas);
goto exit_free;
}
ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags; ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
while (RTA_OK (rta, rtasize)) while (RTA_OK (rta, rtasize))
@ -565,9 +574,11 @@ getifaddrs (struct ifaddrs **ifap)
that we have holes in the interface part of the list, that we have holes in the interface part of the list,
but we always have already the interface for this address. */ but we always have already the interface for this address. */
ifa_index = newlink + newaddr_idx; ifa_index = newlink + newaddr_idx;
ifas[ifa_index].ifa.ifa_flags int idx = map_newlink (ifam->ifa_index - 1, ifas,
= ifas[map_newlink (ifam->ifa_index - 1, ifas, map_newlink_data, newlink);
map_newlink_data, newlink)].ifa.ifa_flags; if (__builtin_expect (idx == -1, 0))
goto try_again;
ifas[ifa_index].ifa.ifa_flags = ifas[idx].ifa.ifa_flags;
if (ifa_index > 0) if (ifa_index > 0)
ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa; ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
++newaddr_idx; ++newaddr_idx;
@ -747,9 +758,13 @@ getifaddrs (struct ifaddrs **ifap)
/* If we didn't get the interface name with the /* If we didn't get the interface name with the
address, use the name from the interface entry. */ address, use the name from the interface entry. */
if (ifas[ifa_index].ifa.ifa_name == NULL) if (ifas[ifa_index].ifa.ifa_name == NULL)
ifas[ifa_index].ifa.ifa_name {
= ifas[map_newlink (ifam->ifa_index - 1, ifas, int idx = map_newlink (ifam->ifa_index - 1, ifas,
map_newlink_data, newlink)].ifa.ifa_name; map_newlink_data, newlink);
if (__builtin_expect (idx == -1, 0))
goto try_again;
ifas[ifa_index].ifa.ifa_name = ifas[idx].ifa.ifa_name;
}
/* Calculate the netmask. */ /* Calculate the netmask. */
if (ifas[ifa_index].ifa.ifa_addr if (ifas[ifa_index].ifa.ifa_addr
@ -826,6 +841,22 @@ getifaddrs (struct ifaddrs **ifap)
return result; return result;
} }
/* Create a linked list of `struct ifaddrs' structures, one for each
network interface on the host machine. If successful, store the
list in *IFAP and return 0. On errors, return -1 and set `errno'. */
int
getifaddrs (struct ifaddrs **ifap)
{
int res;
do
res = getifaddrs_internal (ifap);
while (res == -EAGAIN);
return res;
}
libc_hidden_def (getifaddrs) libc_hidden_def (getifaddrs)